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_log 上插入了一条记录 user_id = 2notification_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

demo here

此查询消除了您的派生 table,减少了执行时间,并尽早执行交叉连接以减少正在操作的总行数。

但我建议您重新考虑一下。一旦通知和用户 table 达到临界质量,这将创建数以百万计的行来过滤。

一个更好的主意是使用 notification_inbox table 作为 notifications_log table 的对应物。创建通知后,将其放入每个用户的收件箱 table。这样您就可以对单个 table 执行简单查询以确定每个用户的未读通知,而不是执行可能可怕的 cross join.

或者,单个 notification_delivery table,而不是收件箱和日志 tables,它有一个 'read' 标志。这也将允许有针对性的通知,以及批量发送给所有用户。