简体   繁体   English

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

[英]MySql CROSS JOIN between two tables and match with another

first of all sorry for my bad english. 首先,抱歉我的英语不好。 The scenario i have is the following: 我的情况如下:

I am developing a notification services that sends notifications messages to many users. 我正在开发一种将通知消息发送给许多用户的通知服务。 I have the following 3 tables on MySql 我在MySql上有以下3个表

users(user_id)

notifications(notification_id, notification)

notifications_log(notification_log_id, notification_id, user_id)

Every time that a user read a notification, i insert a record on notifications_log table, ex. 每次用户阅读通知时,我都会在notifications_log表上插入一条记录,例如。 John user with user_id = 2 read the notification with notification_id =3 : "This is a notification", and then i insert a record on notifications_lo g with user_id = 2 and notification_id = 3 . 具有user_id = 2 John用户读取了具有notification_id =3的通知:“这是一个通知”,然后我在notifications_lo user_id = 2notification_id = 3 notifications_lo g上插入了一条记录。

There is all ok, but i have to create a query to get all the notifications for all the users that not are inserted on notifications_log. 一切正常,但我必须创建一个查询来获取未插入notifications_log的所有用户的所有通知。 What i have is: 我所拥有的是:

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 */

If there is no records on notifications_log table of user 1, query results show me 如果用户1的notifications_log表上没有记录,查询结果将显示给我

user_id   |   notification        |   notification_id   |  notification_log_id
------------------------------------------------------------------------------    
 - 1      |   Notification_1      |   1                 |  null  
 - 1      |   Notification_2      |   2                 |  null

But if i insert at least 1 record on notifications_log for user and notification_2, then i get empty results, and i should get: 但是,如果我在notifications_log为用户和notification_2插入至少1条记录,则结果为空,我应该得到:

user_id   |   notification      |   notification_id   |  notification_log_id
----------------------------------------------------------------------------    
 - 1      |   Notification_1    |   1                 |  null  

It seems that the query joins the notification_log_id to the other record with null notification_log_id... 该查询似乎将notification_log_id与其他记录合并为空,notification_log_id ...

In short, what I need it is get all the notifications from a especific user that there are not on inserted on the table notifications_log 简而言之,我需要的是从某个特定用户获取所有未在表上插入的通知Notifications_log

Thanks in advance! 提前致谢!

The query you want is probably this one: 您想要的查询可能是以下查询:

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 在这里演示

This query eliminates your derived table, reducing the execution time, and performs the cross join as early as possible to reduce the total number of rows being operating on. 此查询消除了派生表,从而减少了执行时间,并尽早执行交叉连接以减少正在操作的行的总数。

But i'd suggest rethinking this altogether. 但我建议您重新考虑一下。 Once notifications and users table reaches critical mass this is going to create millions upon millions of rows to filter. 一旦通知和用户表达到临界数量,这将创建数以百万计的行进行过滤。

A better idea would be to have a notification_inbox table, as a counterpart to your notifications_log table. 一个更好的主意是拥有一个notification_inbox表,作为与notifications_log表相对应的表。 When a notification is created, place it in the inbox table for each user. 创建通知后,将其放置在每个用户的收件箱表中。 That way you can perform a simple query on a single table to determine unread notifications per user, rather than a potentially horrendously performing cross join . 这样,您可以在单个表上执行简单的查询来确定每个用户的未读通知,而不是潜在地执行cross join联接的可怕问题。

Alternatively again, a single notification_delivery table, rather than inbox and log tables, which has a 'read' flag. 同样,也可以选择一个单独的notification_delivery表,而不是具有“ read”标志的收件箱和日志表。 This would also allow targeted notifications, as well as bulk delivery to all users. 这也将允许有针对性的通知,以及批量交付给所有用户。

It seems like you are on the right track but should just be changing user_id to notification_id in the 2nd to last line: 似乎您走在正确的轨道上,但应该只在第二行到最后一行将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 */

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM