我在餐馆CMS应用程序上工作。我在两个表menu_sections
和menu_items
之间存在多对多关系。该关系通过名为menu_relationships
的表格维护。
举个例子,让我们说名为 Snacks (menu_section_id = 1
)的菜单部分包含一个名为 Pretzels 的菜单项(menu_item_id = 1
)和名为 Desserts (menu_section_id = 2
)的菜单部分包含一个名为 Ice Cream (menu_item_id = 2
)的菜单项,但是 Ice Cream < / em>也包含在另一个名为 Kids Food (menu_section_id = 3
)的菜单部分中。因此,menu_relationships
表中将有3行来映射这3个关系。关系表看起来像这样:
---------------------------------------
| menu_section_id | menu_item_id |
|=====================================|
| 1 | 1 |
|-------------------------------------|
| 2 | 2 |
|-------------------------------------|
| 3 | 2 |
---------------------------------------
到目前为止一切顺利。
我想生成一个结果集,该结果集将返回除了具有给定menu_section_id
的菜单项之外的所有菜单项的名称。因此,要返回菜单项名称,我在menu_items
表上有一个连接。这是SQL:
SELECT menu_section_id, menu_items.menu_item_id, menu_item_name
FROM menu_relationships
JOIN menu_items
ON menu_items.menu_item_id = menu_relationships.menu_item_id
WHERE menu_section_id != 2
结果集将为每个不包含给定menu_section_id的关系提供一行。使用示例数据,我将从关系表中获得两行:
-----------------------------------------------------------
| menu_section_id | menu_item_id | menu_item_name |
|======================================|==================|
| 1 | 1 | Pretzels |
|--------------------------------------|------------------|
| 3 | 2 | Ice Cream |
-----------------------------------------------------------
但我想要的是从结果集中完全排除菜单项,如果它与指定的menu_section_id
有任何关系。换句话说,在这个例子中,我只想将没有关系映射的菜单项的行返回到menu_section_id
的2,我只想返回 Pretzels 排。
我使用GROUP BY
聚合函数尝试使用HAVING
和bit_xor()
进行各种操作,但到目前为止还没有运气来获取我想要的内容。
我可能花了更少的时间来解释这一点,但我希望它能够清晰,因为我可以做到。我希望是的。有人可以帮忙吗?
答案 0 :(得分:2)
这是使用LEFT OUTER JOIN
的一个很好的例子,因为它包含左侧表格中的所有行,并且匹配它可以匹配,并返回NULL
任何不匹配。
基于Mark Breyer的上述示例查询,请参阅此示例:
SELECT R.menu_section_id, I.menu_item_id, I.menu_item_name
FROM menu_items AS I
LEFT OUTER JOIN menu_relationships R on (R.menu_item_id=I.menu_item_id) AND (R.menu_section_id = 2)
mysql优化器实际上可能会将其重写为子查询 - 我不是一个优化专家 - 我会看一下构建索引的方式,看看这种类型的连接是否对你的模式有意义。我还会测试它是否真的更快,因为它实际上更少语义。
答案 1 :(得分:1)
有很多方法可以做到这一点。以下是使用WHERE ... NOT IN (...)
的一个示例:
SELECT
R.menu_section_id,
I.menu_item_id,
I.menu_item_name
FROM menu_items AS I
JOIN menu_relationships AS R
ON R.menu_item_id = I.menu_item_id
WHERE I.menu_item_id NOT IN
(
SELECT menu_item_id
FROM menu_relationships
WHERE menu_section_id = 2
)
答案 2 :(得分:1)
我会使用一个子查询,给我每个menu_item_id,它有menu_section_id 2然后使用NOT IN。你走了:
SELECT menu_section_id, menu_items.menu_item_id, menu_item_name
FROM menu_relationships
JOIN menu_items
ON menu_items.menu_item_id = menu_relationships.menu_item_id
WHERE menu_relationships.menu_item_id NOT IN (
SELECT menu_item_id
FROM menu_relationships
WHERE menu_section_id = 2
);
答案 3 :(得分:0)
我打算建议一个子查询,除了我想提一下子查询可以显着影响你网站的性能。您可能需要考虑缓存选项,以避免因此类问题导致严重的加载时间挂起。
在大多数情况下你会没事的,但是如果你只是向我们展示问题的一部分并且没有提及不相关的细节,那么你很可能正在建立一个网站,你在网页上运行100个这样的查询例如,因为有人在这里提到它而没有提到像这样的复合开销会导致......
就像我说的那样,你可能会没事的。除非您想重新启动服务器,否则不要在子查询中执行子查询。