Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Treten Sie mehreren Tabellen bei und behalten Sie NULL-Werte bei

Wenn Sie einen äußeren Join verwenden und dann eine der "äußeren" Spalten in einer Gleichheitsprüfung im WHERE verwenden -Klausel wandeln Sie Ihren äußeren Join in einen inneren Join um. Dies liegt daran, dass Ihre Bedingung, die den Datenschutz von Posts überprüft, erfordert, dass der Post vorhanden ist:

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

Wenn ein äußerer Join dabei ist, eine Zeile zu erzeugen, die einer Benachrichtigung ohne Post entspricht, würde er die obige Bedingung prüfen. Da die Post nicht da ist, p.privacy würde zu NULL ausgewertet werden , "kontaminieren" beide Seiten des OR , und schließlich die gesamte Bedingung zu false auswerten lassen .

Verschieben dieser Bedingung in den ON Bedingung des Joins wird das Problem beheben:

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

Eine andere Möglichkeit, dies zu beheben, wäre das Hinzufügen eines IS NULL Bedingung zu Ihrem OR , etwa so:

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