Mysql
 sql >> Base de données >  >> RDS >> Mysql

Joindre plusieurs tables, en gardant les valeurs NULL

Lorsque vous utilisez une jointure externe, puis utilisez l'une des colonnes "externes" dans une vérification d'égalité dans WHERE clause, vous convertissez votre jointure externe en jointure interne. C'est parce que votre condition qui vérifie la confidentialité de la publication exige que la publication soit là :

AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)

Lorsqu'une jointure externe est sur le point de produire une ligne correspondant à une notification sans publication, elle vérifie la condition ci-dessus. Puisque le message n'est pas là, p.privacy serait évalué à NULL , "contaminant" les deux côtés du OR , et finalement faire en sorte que toute la condition soit évaluée à false .

Déplacer cette condition dans le ON condition de la jointure résoudra le problème :

SELECT
  u.username AS sender,
  ux.username AS receiver,
  p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
                 AND (p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1))
WHERE f.user_id = 1
  AND fr.user_id = 1
  AND f.status = 1
ORDER BY n.id DESC

Une autre façon de résoudre ce problème serait d'ajouter un IS NULL condition à votre OR , comme ceci :

SELECT
  u.username AS sender,
  ux.username AS receiver,
  p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
WHERE f.user_id = 1
  AND fr.user_id = 1
  AND f.status = 1
  AND (p.privacy IS NULL OR p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1))
ORDER BY n.id DESC