Php MySql在两个表之间交叉连接并与另一个表匹配

Php MySql在两个表之间交叉连接并与另一个表匹配,php,mysql,notifications,Php,Mysql,Notifications,首先为我的英语不好感到抱歉。我的情况如下: 我正在开发一个通知服务,它向许多用户发送通知消息。我在MySql上有以下3个表 用户(用户id) 通知(通知id,通知) 通知日志(通知日志id、通知id、用户id) 每次用户读取通知时,我都会在通知日志表中插入一条记录,例如:John user withuser\u id=2读取带有notification\u id=3的通知:“这是一个通知”,然后我在notification\u log上插入一条记录,其中user\u id=2和notificat

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

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

用户(用户id)

通知(通知id,通知)

通知日志(通知日志id、通知id、用户id)

每次用户读取通知时,我都会在通知日志表中插入一条记录,例如:John user with
user\u id=2
读取带有
notification\u id=3
的通知:“这是一个通知”,然后我在
notification\u lo
g上插入一条记录,其中
user\u id=2
notification\u 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的通知日志表中没有记录,则查询结果显示

user_id   |   notification        |   notification_id   |  notification_log_id
------------------------------------------------------------------------------    
 - 1      |   Notification_1      |   1                 |  null  
 - 1      |   Notification_2      |   2                 |  null
但是,如果我在
notifications\u log
中为user和notification\u 2插入至少一条记录,那么我会得到空结果,我应该得到:

user_id   |   notification      |   notification_id   |  notification_log_id
----------------------------------------------------------------------------    
 - 1      |   Notification_1    |   1                 |  null  
查询似乎将通知\u日志\u id与另一个通知\u日志\u id为空的记录连接起来

简言之,我需要的是从一个特定的用户那里获取表notifications_log中没有插入的所有通知


提前谢谢

看起来您的思路是正确的,但应该将第二行到最后一行的用户id更改为通知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 */

看起来您的思路是正确的,但应该将第二行到最后一行的用户id更改为通知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

此查询消除了派生表,减少了执行时间,并尽早执行交叉联接,以减少对其进行操作的总行数

但我建议大家重新考虑一下。一旦notifications and users表达到临界质量,这将创建数以百万计的行进行过滤

一个更好的主意是有一个通知收件箱表,作为通知日志表的对应项。创建通知后,将其放在每个用户的收件箱表中。这样,您就可以在单个表上执行一个简单的查询,以确定每个用户的未读通知,而不是执行一个潜在的可怕的交叉连接


或者,也可以使用单个通知传递表,而不是具有“读取”标志的收件箱和日志表。这也将允许有针对性的通知,以及批量交付给所有用户。

您想要的查询可能是:

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

此查询消除了派生表,减少了执行时间,并尽早执行交叉联接,以减少对其进行操作的总行数

但我建议大家重新考虑一下。一旦notifications and users表达到临界质量,这将创建数以百万计的行进行过滤

一个更好的主意是有一个通知收件箱表,作为通知日志表的对应项。创建通知后,将其放在每个用户的收件箱表中。这样,您就可以在单个表上执行一个简单的查询,以确定每个用户的未读通知,而不是执行一个潜在的可怕的交叉连接


或者,也可以使用单个通知传递表,而不是具有“读取”标志的收件箱和日志表。这也将允许有针对性的通知,以及批量交付给所有用户。

执行时间让我担心,但这样做似乎会很快。您的代码工作得很好,非常感谢!:)@Agustinancolasbusso随着表大小的增加,情况会呈指数级恶化。如果有1000个用户,有1000个通知,则可以处理1000000行。现在可能不是问题,但以后。。。取决于此系统的使用率:)但是,如果它满足您的要求,您可以将其标记为已接受吗?您是对的,我将使用删除最早的通知的批处理过程来处理通知(因为业务模型允许我这样做)。谢谢朋友@阿古斯丁·尼古拉斯·布索听起来是个不错的主意——如果你对这个答案感到满意,你能把它标记为被接受,这样它就有可能帮助其他人吗?干杯执行时间让我很担心,但有了这个,它看起来会很快。您的代码工作得很好,非常感谢!:)@Agustinancolasbusso随着表大小的增加,情况会呈指数级恶化。如果有1000个用户,有1000个通知,则可以处理1000000行。现在可能不是问题,但以后。。。取决于此系统的使用率:)但是,如果它满足您的要求,您可以将其标记为已接受吗?您是对的,我将使用删除最早的通知的批处理过程来处理通知(因为业务模型允许我这样做)。谢谢朋友@阿古斯丁·尼古拉斯·布索听起来是个不错的主意——如果你对这个答案感到满意,你能把它标记为被接受,这样它就有可能帮助其他人吗?干杯,谢谢你,史蒂夫!但我尝试了这些改变,但没有效果。查询显示空结果pala_uuu回答工作正常。再次感谢!非常感谢史蒂夫!但我尝试了这些改变,但没有效果。查询显示空结果pala_uuu回答工作正常。再次感谢!顺便说一句,你的英语很好。可能有4到5个小的语法错误。就这些。顺便说一句,你的英语很好。可能有4到5个小的语法错误。这就是全部。