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 连接查询 - 如何获得精确匹配的主要内容,如果未能解决你的问题,请参考以下文章

LDAP在JAVA中如何模糊查询

访问sql查询连接匹配有两个匹配的连接行

MS Access 内连接不精确匹配(通配符或类似)

在 SQL 连接语句中选择一对多关系中最匹配的记录

SQL连接查询

基于 SQL 查询中最接近的文本匹配连接表?