SQL 连接查询 - 如何获得精确匹配
Posted
技术标签:
【中文标题】SQL 连接查询 - 如何获得精确匹配【英文标题】:SQL Junction Query - How To Get Exact Match 【发布时间】:2015-03-03 20:49:24 【问题描述】:我希望这个问题的答案与 DBMS 无关,但如果相关,我正在使用 Access SQL。
请注意,这是我正在尝试做的简化版本。
现在,考虑一下我有以下三个表。
我的主要水果桌(tblFruits):
╔═════════╦═══════════╦
║ fruitID ║ fruitName ║
╠═════════╬═══════════╬
║ 1 ║ Apple ║
║ 2 ║ Orange ║
║ 3 ║ Grapefruit║
╚═════════╩═══════════╩
将许多标签链接到 1 个水果的联结表(tblFruitTagJunc):
╔════════════════╦═════════╦═════════════╗
║ fruitTagJuncID ║ fruitID ║ tagID ║
╠════════════════╬═════════╬═════════════╣
║ 1 ║ 1 ║ 1 ║
║ 2 ║ 1 ║ 2 ║
║ 3 ║ 1 ║ 4 ║
║ 4 ║ 1 ║ 5 ║
║ 5 ║ 2 ║ 3 ║
║ 6 ║ 3 ║ 3 ║
║ 7 ║ 3 ║ 6 ║
╚════════════════╩═════════╩═════════════╝
最后是一个标签表来标记我的水果(tblTag):
╔═════════╦═══════════╗
║ tagID ║ tag ║
╠═════════╬═══════════╣
║ 1 ║ Tasty ║
║ 2 ║ Red ║
║ 3 ║ Orange ║
║ 4 ║ Shiny ║
║ 5 ║ Delicious ║
║ 6 ║ Awful ║
╚═════════╩═══════════╝
感谢This Blog Post让我偷懒)
这基本上是说:
-
苹果是(红色、有光泽、美味、美味)
橙子是(橙子)
葡萄柚是(橙色,可怕)
现在说我想选择那些带有“橙色”标签的水果,而没有其他水果。有了提供的数据,那将是只有fruitName = 'Orange'
的数据。我目前正在这样做:
SELECT F.fruitName
FROM tblFruits F
INNER JOIN tblFruitTagJunc AS FTJ on F.fruitID = FTJ.fruitID
INNER JOIN tbltag as T ON FTJ.tagID = T.tagID
WHERE T.tag in('Orange')
GROUP BY F.fruitName
HAVING count(T.tag) = 1
这将在结果中同时返回 Orange 和 Grapfruit,但我只想要 Orange。
我这样做 SQL 语句的原因是不同类型的水果可能具有相同的名称但不同的标签,或者不同的水果可能只有一个相同的标签。
编辑:
SQLFiddle as requested.
【问题讨论】:
请注意,tblFruitTagJunc.fruitTagJuncID
列对您没有任何好处。你最好放弃它(以及它的相关索引,假设它是一个 PK)。既然您无论如何都需要 (fruitId, tagId) 上的唯一索引,只需将其设为 PK。
所以当你说你只想选择 Oranges 时,是指fruitName = 'Orange'
还是fruitID = 2
?
HAVING count(T.tag) = 1
给你的水果只有一个标签。因此不需要where t.tag in ('Orange')
。您的查询失败,因为您仅限于那些橙色的标签..已经排除了糟糕的标签(葡萄柚很好吃)
@JohnBollinger 我已经读过很多次了,拥有独立的 PK 并且不需要它比没有它并且以后需要它要好。由于我遇到的大多数连接表都没有那么大,所以我总是尝试包含它。虽然我确实看到了这两种方式的利弊。
@Elias,最好不要也不需要。
【参考方案1】:
您在正确的轨道上,但您需要在 having
子句而不是 where
子句中进行条件聚合。当您使用where
时,您永远不会看到其他标签。
所以:
SELECT F.fruitName
FROM tblFruits as F INNER JOIN
tblFruitTagJunc AS FTJ
on F.fruitID = FTJ.fruitID INNER JOIN
tbltag as T
ON FTJ.tagID = T.tagID
GROUP BY F.fruitName
HAVING SUM(iif(t.tag in ('Orange'), 1, 0) > 0 AND
COUNT(t.tag) = 1;
请注意,表达条件的“正确”方式是使用CASE
而不是IIF()
。此外,Access 通常需要在连接周围加上很多难看的括号,我也省略了。
【讨论】:
这可以扩展到多个标签吗?例如。如果我有一个Round
标签并且橙子和葡萄柚都与它相关联,那么该声明是否适用于iif(t.tag in ("Orange","Round")...
?根据我下面的 Sql Fiddle,不是吗? sqlfiddle.com/#!2/74bd90/1
没关系,我的小错误。我忘记将计数切换为 2。感谢您的帮助。以上是关于SQL 连接查询 - 如何获得精确匹配的主要内容,如果未能解决你的问题,请参考以下文章