我有4个表user
,posts
,follows
,notifications
。 posts
表中有一个名为privacy
的字段,其中值1表示“任何人都可以看到”,2表示“只有朋友可以看到”。
我的notifications
表格如下:
id user_id tonotify_id notification post_id
1 2 3 --- 1
2 3 2 --- 2
3 2 4 --- 3
我的follows
表看起来像这样:
id user_id tofollow_id status fstatus
1 1 2 1 1
2 1 3 1 1
字段fstatus
值为1表示他们也是朋友。
现在我正在尝试让某个用户关注的人发送所有通知(比如说id为1的用户)。假设1跟随用户2和3,我需要从上表中获取所有通知。但是,在此之前,我需要确保帖子(由tonotify_id
列中的用户发布)可用。也就是说,我需要检查隐私设置。我有以下代码:
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 = 1 OR (p.privacy = 2 AND fr.fstatus = 1)
ORDER BY n.id DESC
除了一个小故障外,它似乎正在起作用。由于用户1没有关注用户4所有针对4的通知,即使帖子是公开的也不显示。我的猜测与JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
有关,因为用户1没有跟随4,因此没有与此连接匹配的行。有什么建议可以解决这个问题吗?
答案 0 :(得分:1)
我确实尝试了[外连接],但输出是相同的。
当您使用外部联接,然后在WHERE
子句中的相等性检查中使用其中一个“外部”列时,将外部联接转换为内部联接。这是因为您检查帖子隐私的条件需要帖子在那里:
AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)
当外部联接即将生成与没有帖子的通知相对应的行时,它将检查上述条件。由于帖子不存在,p.privacy
将评估为NULL
,“污染”OR
的两侧,并最终使整个条件评估为false
。
将此条件移至联接的ON
条件将解决问题:
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
解决此问题的另一种方法是向IS NULL
添加OR
条件,如下所示:
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
答案 1 :(得分:0)
您需要使用LEFT JOIN
之类的外部联接,而不是仅使用JOIN
使用内部联接。外连接将始终从一个“侧”返回行(这就是为什么它被称为LEFT [OUTER] JOIN
和RIGHT [OUTER] JOIN
),即使另一个“侧”与任何东西都不匹配。