Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Junte-se a várias tabelas, mantendo NULLs


Quando você usa uma junção externa e, em seguida, usa uma das colunas "externas" em uma verificação de igualdade no WHERE cláusula, você converte sua junção externa em uma junção interna. Isso ocorre porque sua condição que verifica a privacidade da postagem exige que a postagem esteja lá:
AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)

Quando uma junção externa está prestes a produzir uma linha que corresponde a uma notificação sem uma postagem, ela verifica a condição acima. Como a postagem não está lá, p.privacy avaliaria para NULL , "contaminando" ambos os lados do OR , e eventualmente fazendo com que toda a condição seja avaliada como false .

Movendo esta condição para ON condição da junção irá corrigir o problema:
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

Outra maneira de corrigir isso seria adicionar um IS NULL condição para o seu OR , assim:
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