MySql 两个表之间的 CROSS JOIN 并与另一个表匹配
MySql CROSS JOIN between two tables and match with another
首先抱歉我的英语不好。我的场景如下:
我正在开发一个向许多用户发送通知消息的通知服务。我在 MySql
上有以下 3 tables
users(user_id)
notifications(notification_id, notification)
notifications_log(notification_log_id, notification_id, user_id)
每次用户阅读通知时,我都会在 notifications_log table 上插入一条记录,例如。 user_id = 2
的 John 用户阅读了 notification_id =3
的通知:"This is a notification",然后我在 notifications_lo
g 上插入了一条记录 user_id = 2
和 notification_id = 3
。
一切正常,但我必须创建一个查询来获取未在 notifications_log 上插入的所有用户的所有通知。我拥有的是:
SELECT u.user_id, n.notification_id, n.notification, nl.notification_log_id
FROM users as u
LEFT JOIN notifications_log as nl ON nl.user_id = u.user_id
CROSS JOIN notifications as n
WHERE u.user_id NOT IN (SELECT nl.user_id FROM notifications_log as nl)
AND u.user_id = 1 /* test with user 1 */
如果用户1的notifications_logtable上没有记录,查询结果显示给我
user_id | notification | notification_id | notification_log_id
------------------------------------------------------------------------------
- 1 | Notification_1 | 1 | null
- 1 | Notification_2 | 2 | null
但是如果我在 notifications_log
上为用户和 notification_2 插入至少 1 条记录,那么我得到空结果,我应该得到:
user_id | notification | notification_id | notification_log_id
----------------------------------------------------------------------------
- 1 | Notification_1 | 1 | null
似乎查询将 notification_log_id 连接到另一条空记录 notification_log_id...
简而言之,我需要的是从特定用户那里获取所有未插入 table notifications_log
的通知
提前致谢!
看来您的方向是正确的,但应该只是将 user_id 更改为 notification_id在倒数第二行:
SELECT u.user_id, n.notification_id, n.notification, nl.notification_log_id
FROM users as u
LEFT JOIN notifications_log as nl ON nl.user_id = u.user_id
CROSS JOIN notifications as n
WHERE n.notification_id NOT IN (SELECT nl.notification_id FROM notifications_log as nl)
AND u.user_id = 1 /* test with user 1 */
你要查询的可能是这个:
select n.notification_id, u.user_id
from notifications n
cross join users u
left join notifications_log nl
on n.notification_id = nl.notification_id
and nl.user_id = u.user_id
where nl.notification_log_id is null
此查询消除了您的派生 table,减少了执行时间,并尽早执行交叉连接以减少正在操作的总行数。
但我建议您重新考虑一下。一旦通知和用户 table 达到临界质量,这将创建数以百万计的行来过滤。
一个更好的主意是使用 notification_inbox table 作为 notifications_log table 的对应物。创建通知后,将其放入每个用户的收件箱 table。这样您就可以对单个 table 执行简单查询以确定每个用户的未读通知,而不是执行可能可怕的 cross join
.
或者,单个 notification_delivery table,而不是收件箱和日志 tables,它有一个 'read' 标志。这也将允许有针对性的通知,以及批量发送给所有用户。
首先抱歉我的英语不好。我的场景如下:
我正在开发一个向许多用户发送通知消息的通知服务。我在 MySql
上有以下 3 tablesusers(user_id)
notifications(notification_id, notification)
notifications_log(notification_log_id, notification_id, user_id)
每次用户阅读通知时,我都会在 notifications_log table 上插入一条记录,例如。 user_id = 2
的 John 用户阅读了 notification_id =3
的通知:"This is a notification",然后我在 notifications_lo
g 上插入了一条记录 user_id = 2
和 notification_id = 3
。
一切正常,但我必须创建一个查询来获取未在 notifications_log 上插入的所有用户的所有通知。我拥有的是:
SELECT u.user_id, n.notification_id, n.notification, nl.notification_log_id
FROM users as u
LEFT JOIN notifications_log as nl ON nl.user_id = u.user_id
CROSS JOIN notifications as n
WHERE u.user_id NOT IN (SELECT nl.user_id FROM notifications_log as nl)
AND u.user_id = 1 /* test with user 1 */
如果用户1的notifications_logtable上没有记录,查询结果显示给我
user_id | notification | notification_id | notification_log_id
------------------------------------------------------------------------------
- 1 | Notification_1 | 1 | null
- 1 | Notification_2 | 2 | null
但是如果我在 notifications_log
上为用户和 notification_2 插入至少 1 条记录,那么我得到空结果,我应该得到:
user_id | notification | notification_id | notification_log_id
----------------------------------------------------------------------------
- 1 | Notification_1 | 1 | null
似乎查询将 notification_log_id 连接到另一条空记录 notification_log_id...
简而言之,我需要的是从特定用户那里获取所有未插入 table notifications_log
的通知提前致谢!
看来您的方向是正确的,但应该只是将 user_id 更改为 notification_id在倒数第二行:
SELECT u.user_id, n.notification_id, n.notification, nl.notification_log_id
FROM users as u
LEFT JOIN notifications_log as nl ON nl.user_id = u.user_id
CROSS JOIN notifications as n
WHERE n.notification_id NOT IN (SELECT nl.notification_id FROM notifications_log as nl)
AND u.user_id = 1 /* test with user 1 */
你要查询的可能是这个:
select n.notification_id, u.user_id
from notifications n
cross join users u
left join notifications_log nl
on n.notification_id = nl.notification_id
and nl.user_id = u.user_id
where nl.notification_log_id is null
此查询消除了您的派生 table,减少了执行时间,并尽早执行交叉连接以减少正在操作的总行数。
但我建议您重新考虑一下。一旦通知和用户 table 达到临界质量,这将创建数以百万计的行来过滤。
一个更好的主意是使用 notification_inbox table 作为 notifications_log table 的对应物。创建通知后,将其放入每个用户的收件箱 table。这样您就可以对单个 table 执行简单查询以确定每个用户的未读通知,而不是执行可能可怕的 cross join
.
或者,单个 notification_delivery table,而不是收件箱和日志 tables,它有一个 'read' 标志。这也将允许有针对性的通知,以及批量发送给所有用户。