使用n:m关系连接3个表,希望看到不匹配的行

时间:2011-11-04 18:07:03

标签: mysql join

对于此问题,请考虑以下3个表:

Event
id (pk)
title

Event_Category
event_id (pk, fk)
category_id (pk, fk)

Category
id (pk)
description

我觉得很琐碎...... :)每个事件都可以分为零个或多个类别,总共有4个类别。 在我的应用程序中,我想查看和编辑特定事件的类别。在图形上,事件将与所有类别一起显示,并且复选框将指示事件是否属于该类别。更改和保存选择将导致中间表Event_Category的修改。 但首先:如何为特定事件选择此项?我需要的查询实际上总是返回4行,即存在的类别数。

以下仅返回id = 11的事件所属类别的条目。尝试使用外连接并未在结果中提供更多行。

SELECT e.id, c.omschrijving 
FROM Event e
  INNER JOIN Event_Categorie ec ON e.id = ec.event_id
  INNER JOIN Categorie c ON c.id = ec.categorie_id
WHERE e.id = 11

或者我应该从查询中的Category表开始?希望有一些提示:) TIA,Klaas

更新 是的我做了但仍未找到答案。但是我通过从查询中省略Event表来简化了这个问题,因为该表仅用于查看事件描述。

SELECT * from Categorie c LEFT JOIN Event_Categorie ec ON c.id = ec.categorie_id WHERE ec.event_id = 11;

简化的2表查询仅使用查找表和链接表,但仍然只返回2行,而不是在Categorie表中返回总共4行。 我的猜测是在加入后应用了WHERE子句,因此排除了未加入链接表的行。在我的应用程序中,我使用子查询解决了问题,但我仍然想知道什么是最佳解决方案。

4 个答案:

答案 0 :(得分:0)

您想要的是所有类别的列表,以及有关该类别是否在您的活动类别列表中的信息。

所以,你可以这样做:

SELECT 
    * 
FROM 
    Category 
    LEFT JOIN Event_Category ON category_id = id 
WHERE 
    event_id = 11
对于不属于您事件的类别,

和event_id列将为NULL。

您还可以创建一个列(下面名为has_category),用于查看事件是否具有此类别而不是与NULL进行比较:

SELECT 
    *,
    event_id IS NOT NULL AS has_category
FROM 
    Category 
    LEFT JOIN Event_Category ON category_id = id 
WHERE 
    event_id = 11

编辑:这看起来就像你说你在编辑时所做的那样。我测试了它似乎是正确的。你确定你正在运行这个查询,并且那些带有NULL的行不会被忽略吗?

答案 1 :(得分:0)

查询

SELECT * FROM Categorie;

返回4行:

+----+--------------+-------------------------------------+--------------------------------------+
| id | omschrijving | afbeelding                          | afbeelding_klein                     |
+----+--------------+-------------------------------------+--------------------------------------+
|  1 | Creatief     | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg  |
|  2 | Sportief     | images/categorieen/sportief420k.jpg | images/categorieen/sportief190kr.jpg |
|  4 | Culinair     | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg  |
|  5 | Spirit       | images/categorieen/spirit420k.jpg   | images/categorieen/spirit190k.jpg    |
+----+--------------+-------------------------------------+--------------------------------------+
4 rows in set (0.00 sec)

BUT: 查询

SELECT * 
FROM Categorie 
LEFT JOIN Event_Categorie ON categorie_id = id 
WHERE event_id = 11;

返回2行:

+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+
| id | omschrijving | afbeelding                          | afbeelding_klein                    | event_id | categorie_id |
+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+
|  1 | Creatief     | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg |       11 |            1 |
|  4 | Culinair     | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg |       11 |            4 |
+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+
2 rows in set (0.00 sec)

所以我仍然需要子查询...并且LEFT JOIN在显示CAtegorie表的所有行时无效,无论是否与链接表匹配。

然而,这个查询做了我想要它做的事情:

SELECT * 
FROM Categorie c 
LEFT JOIN (SELECT * FROM Event_Categorie ec WHERE ec.event_id = 11 ) AS subselect ON  subselect.categorie_id = c.id;

结果:

+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+
| id | omschrijving | afbeelding                          | afbeelding_klein                     | event_id | categorie_id |
+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+
|  1 | Creatief     | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg  |       11 |            1 |
|  2 | Sportief     | images/categorieen/sportief420k.jpg | images/categorieen/sportief190kr.jpg |     NULL |         NULL |
|  4 | Culinair     | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg  |       11 |            4 |
|  5 | Spirit       | images/categorieen/spirit420k.jpg   | images/categorieen/spirit190k.jpg    |     NULL |         NULL |
+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+
4 rows in set (0.00 sec)

答案 2 :(得分:0)

问题是您已经通过eventid过滤了结果。正如您在结果中看到的那样,两个类别(Sportief和Spirit)没有事件。因此,正确的SQL语句(使用SQL Server语法;可能需要一些翻译)是:

SELECT * 
FROM Categorie 
LEFT JOIN Event_Categorie ON categorie_id = id 
WHERE (event_id IS NULL) OR (event_id = 11);

答案 3 :(得分:0)

最后我找到了正确的查询,没有必要进行子选择。但WHERE子句在加入后起作用,因此不再是连接的一部分。该解决方案是使用额外条件扩展ON子句。现在,对于不匹配的类别,所有4行都返回NULL;

SELECT * 
FROM Categorie  
LEFT JOIN Event_Categorie ON categorie_id = id AND event_id = 11;

所以底线是在ON子句中添加一个额外条件与在WHERE子句中按相同条件过滤掉行的效果不同!