【问题标题】:MySql CROSS JOIN between two tables and match with anotherMySql CROSS JOIN 在两个表之间并与另一个匹配
【发布时间】:2015-05-21 02:07:54
【问题描述】:

首先抱歉我的英语不好。我的情况如下:

我正在开发一个向许多用户发送通知消息的通知服务。我在 MySql 上有以下 3 个表

users(user_id)

notifications(notification_id, notification)

notifications_log(notification_log_id, notification_id, user_id)

每次用户阅读通知时,我都会在通知日志表中插入一条记录,例如。使用user_id = 2 的John 用户使用notification_id =3 阅读通知:“这是一个通知”,然后我在notifications_log 上插入一条记录,使用user_id = 2notification_id = 3

一切正常,但我必须创建一个查询来获取所有未插入到通知日志中的用户的所有通知。我有的是:

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_log表没有记录,查询结果显示我

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为空的记录...

简而言之,我需要的是获取来自特定用户的所有通知,这些通知没有插入到表通知日志中

提前致谢!

【问题讨论】:

  • 顺便说一句,你的英语很好。可能有 4 或 5 个小语法错误。就是这样。

标签: php mysql notifications


【解决方案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

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

但我建议完全重新考虑这一点。一旦通知和用户表达到临界质量,这将创建数百万行进行过滤。

一个更好的主意是有一个 notification_inbox 表,作为你的 notifications_log 表的对应物。创建通知后,将其放置在每个用户的收件箱表中。这样,您就可以对单个表执行简单的查询,以确定每个用户的未读通知,而不是像 cross join 那样执行可怕的操作。

另外,一个单一的 notification_delivery 表,而不是具有“已读”标志的收件箱和日志表。这也将允许有针对性的通知,以及批量发送给所有用户。

【讨论】:

  • 执行时间让我担心,但这样看起来会很快。您的代码完美运行,非常感谢! :)
  • @AgustinNicolasBusso 随着您的桌子大小的增加,它会呈指数级恶化。如果有 1000 个用户,有 1000 条通知,则需要处理 1,000,000 行。现在可能不是问题,但稍后...取决于这个系统有多少使用:) 但是如果它满足您的要求,您能否将其标记为已接受?
  • 你是对的,我将使用删除最旧的批处理来处理通知(因为商业模式允许我这样做)。谢谢朋友!
  • @AgustinNicolasBusso 听起来是个不错的主意 - 如果您对这个答案感到满意,您能否将其标记为已接受,这样它可能会帮助其他人?欢呼
【解决方案2】:

您似乎走在正确的轨道上,但应该只是在倒数第二行将 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 */

【讨论】:

  • 非常感谢史蒂夫!但我尝试更改但不起作用。查询显示空结果pala_回答工作正常。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-15
  • 2012-02-04
  • 1970-01-01
  • 1970-01-01
  • 2017-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多