MySQL - 两个表和两个连接

Posted

技术标签:

【中文标题】MySQL - 两个表和两个连接【英文标题】:MySQL - two tables and two joins 【发布时间】:2019-10-23 11:20:54 【问题描述】:

我被一个查询困住了,我想做几件事: - 我有一张桌子,里面有一些活动,每个活动都有有限的人数可以申请 - 在其他表中,我记录了谁申请了哪个事件 - 在网站上,对用户,我只想显示他可以申请的事件(更准确地说,他没有申请的事件;一旦他申请,该事件应该不再对用户可见) AND/OR 申请人数少于 max_no_people (当活动已满时,无需向用户显示

我在另一个线程中从这里获得了帮助,但仅针对部分问题。 表格如下所示:

other_events (eventID, max_no_people, active)
event_applied (eventID, userID)

这里是查询:

SELECT count(event_applied.eventid) AS no_applied, 
       e.eventID, e.max_no_people, e.active 
FROM other_events e 
     INNER JOIN 
     event_applied ON event_applied.eventID = e.eventID 
     LEFT JOIN 
     event_applied ea ON ea.eventID 
                      AND event_applied.userID = :userID 
WHERE ea.eventID IS NULL 
      AND e.active = 1
GROUP BY event_applied.eventID 
HAVING (no_applied < max_no_people)

此查询工作正常 - 但是 - 对于除当前选定用户之外的所有其他用户。 假设您有 userID = 42(不在与 eventID = 123 配对的 events_applied 表中):

其他事件

eventID | max_no_people | active
--------|---------------|-------
   21   |       5       |   1

在 events_applied 中

eventID | userID
--------|-------
123     |  10
123     |  11
123     |  12
123     |  13
123     |  14

查询将返回空行(因为事件已用完,您无法再申请),但如果您是 userID = 12(在 events_applied 表中且有 eventID 对),则结果将如下所示:

no_applied | e.eventID | e.max_no_people | e.active
-----------|-----------|-----------------|---------
 **4**     |     123   |         5       |    1

因此,该事件将是可见的,您将能够一次又一次地应用(我知道我必须添加一些额外的控件,但我稍后会解决)。

所以,问题在于这个查询以某种方式丢弃了当前用户的行并且没有将其添加到最终计数中。

有人吗? :)

【问题讨论】:

您说:一旦他申请,该事件应该不再对用户可见。所以对于userID = 12,你不希望查询返回一个空的结果集,因为他已经申请了事件123 我想我说错了 - 一旦他申请,是的,该事件应该不再对用户可见。但它仍然可见并且计数仍然是 4(就像它不会计算您自己的应用程序一样)我在文本中进行了编辑和澄清 【参考方案1】:

您的查询的主要问题是您没有关联left joined 查询与特定的eventID

考虑以下代码:

SELECT 
    COUNT(*) AS no_applied, 
    e.eventID, 
    e.max_no_people, 
    e.active 
FROM 
    other_events e 
    INNER JOIN event_applied ea1 ON ea1.eventID = e.eventID 
    LEFT JOIN event_applied ea2 ON ea1.eventID = ea2.eventID AND ea2.userID = :userID
WHERE ea2.eventID IS NULL AND e.active = 1
GROUP BY e.eventID, e.max_no_people, e.active 
HAVING (no_applied < e.max_no_people)

如果您使用示例数据运行此查询 in this DB Fiddle

userID = 42,不返回记录:这是因为没有可用的事件(只有一个事件,已经满了)

使用userID = 12,它不返回任何记录:这是因为该用户已经申请了唯一可用的事件

我建议创建一个更具代表性的数据集,例如创建另一个未满的事件,这样您就可以彻底验证查询。

【讨论】:

只是一个简单的问题 - 您将如何改进此查询以显示尚未申请的事件? 因为现在如果我创建一个新事件,这个事件在 event_applied 表中不存在,也不会出现。我必须在事件应用表中手动插入该 eventID 的内容才能将其放入 COUNT() @Nikola:对于这个猜测,您只需将第一个 INNER JOIN 更改为 LEFT JOIN【参考方案2】:

问题在于,在您当前的查询中,您只是明确排除了用户应用的条目,因此计数减一。相反,您需要排除它们应用的所有事件。

由于您使用的是 LEFT JOIN,因此您需要使用子查询来选择所有这些事件,然后仅加入事件(而不加入用户)。

SELECT count(event_applied.eventid) AS no_applied, e.eventID, e.max_no_people, e.active 
FROM other_events e 
INNER JOIN event_applied ON event_applied.eventID = e.eventID 
LEFT JOIN (SELECT * FROM event_applied WHERE event_applied.userID = :userID ) ea 
ON ea.eventID = e.eventID 
WHERE ea.eventID IS NULL AND e.active = 1
GROUP BY e.eventID, e.max_no_people, e.active
HAVING (no_applied < max_no_people)

【讨论】:

【参考方案3】:

感谢Graeme Tate 和GMB,这两种方法都非常有效! 我今天学到了一些新东西:)

【讨论】:

以上是关于MySQL - 两个表和两个连接的主要内容,如果未能解决你的问题,请参考以下文章

mysql中两个大表之间的连接查询

mysql 自连接查询

MySQL多表连接查询

MySQL表连接之驱动表与被驱动表

SQL - 从一个表中选择,同时在另外两个表之间进行内部连接(多对多表和另一个表)

mysql学习笔记—— MySQL内连接和外连接