Mysql SQL联接查询以返回在联接表中未找到匹配项的行
更多的是一个理论/逻辑问题,但我有两个表:Mysql SQL联接查询以返回在联接表中未找到匹配项的行,mysql,sql,join,Mysql,Sql,Join,更多的是一个理论/逻辑问题,但我有两个表:链接和选项。Links是一个表,我在其中添加表示产品ID(在单独的products表中)和选项之间链接的行。选项表包含所有可用选项 我试图做的(但很难创建逻辑)是连接两个表,只返回links表中没有选项链接的行,因此表示哪些选项仍然可以添加到产品中 SQL有没有一个特性可以帮助我?我对SQL还没有太多的经验。是的,你可以做一个左连接(如果是MySQL;其他方言也有变化),它将包括链接中选项不匹配的行。然后测试选项。someColumn为空,链接中的行在选
链接
和选项
。Links是一个表,我在其中添加表示产品ID(在单独的products
表中)和选项之间链接的行。选项表包含所有可用选项
我试图做的(但很难创建逻辑)是连接两个表,只返回links
表中没有选项链接的行,因此表示哪些选项仍然可以添加到产品中
SQL有没有一个特性可以帮助我?我对SQL还没有太多的经验。是的,你可以做一个左连接(如果是MySQL;其他方言也有变化),它将包括链接中选项不匹配的行。然后测试选项。someColumn
为空
,链接中的行在选项中没有“匹配”行。尝试类似的方法
计算
SELECT Links.linkId, Count(*)
FROM Link
LEFT JOIN Options ON Links.optionId = Options.optionId
Where Options.optionId IS NULL
Group by Links.linkId
看台词
SELECT Links.linkId
FROM Link
LEFT JOIN Options ON Links.optionId = Options.optionId
Where Options.optionId IS NULL
你的桌子设计听起来不错
如果此查询返回链接到特定“产品”的“选项”的id
值
然后此查询将获得与“产品”相关的所有选项的详细信息
注意,我们实际上可以将“product_id='foo'”
谓词从连接的WHERE子句移动到ON子句,以获得等效的结果,例如
SELECT o.id
, o.name
FROM options o
JOIN links k
ON k.option_id = o.id
AND k.product_id = 'foo'
(这并不是说它在这里有什么区别,但如果我们使用外部联接,它会有所不同(在WHERE子句中,它会否定联接的“外部性”,并使其等效于内部联接。)
但是,这些都不能回答你的问题,它只是为回答你的问题设置了舞台:
如何从“选项”中获取未链接到特定产品的行?
最有效的方法(通常)是反连接模式
也就是说,我们将获得“选项”中的所有行,以及“链接”中的任何匹配行(在您的情况下,对于特定的产品id)。该结果集将包括“选项”中的行,这些行在“链接”中没有匹配行
“诀窍”是过滤掉在“链接”中找到的所有匹配行。这将只剩下不匹配的行
我们过滤这些行的方式是,在WHERE子句中使用一个谓词来检查是否找到了匹配项。我们通过检查一列来做到这一点,我们知道如果找到了匹配的行,该列肯定是非NULL。如果找到了匹配的行,我们肯定知道*该列肯定是NULL
大概是这样的:
SELECT o.id
, o.name
FROM options o
LEFT
JOIN links k
ON k.option_id = o.id
AND k.product_id = 'foo'
WHERE k.option_id IS NULL
“LEFT”
关键字指定一个“outer”联接操作,我们从“options”(联接“LEFT”侧的表)获取所有行,即使找不到匹配的行。(正常的内部联接将过滤掉不匹配的行。)
“诀窍”在WHERE子句中……如果我们从链接中找到匹配的行,我们知道从“links”
返回的“option\u id”
列不会为NULL。如果它“等于”某个值,它就不能为NULL,我们知道它必须“等于”某个值,因为ON子句中的谓词
因此,我们知道选项中没有匹配项的行对于该列将具有空值
这需要一点时间让你的大脑围绕它,但反连接很快成为一种熟悉的模式
“反连接”模式不是获得结果集的唯一方法。还有其他几种方法
一种选择是将带有“NOT EXISTS”
谓词的查询与相关子查询一起使用。这稍微容易理解,但通常不会执行:
SELECT o.id
, o.name
FROM options o
WHERE NOT EXISTS ( SELECT 1
FROM links k
WHERE k.option_id = o.id
AND k.product_id = 'foo'
)
也就是说,从选项表中获取所有行。但对于每一行,运行一个查询,查看链接表中是否“存在”匹配行。(选择列表中返回的内容无关紧要,我们只是测试它是否返回至少一行……我在选择列表中使用“1”来提醒我正在查找“1行”
这通常不如反连接执行得好,但有时它确实运行得更快,特别是当外部查询的WHERE子句中的其他谓词过滤掉几乎每一行,并且子查询只需运行几行时。(也就是说,当我们只需要检查一堆干草中的几根针时。当我们需要处理整堆干草时,反连接模式通常更快。)
您最有可能看到的初学者查询是不在(子查询)
。我甚至不想给出一个这样的例子。如果您有一个文本列表,那么无论如何,请使用不在。但是对于子查询,它很少是最好的执行者,尽管它似乎是最容易理解的
哦,真糟糕,我也会给你一个演示(不是我鼓励你这样做):
该子查询(在参数内)获取与产品关联的所有选项id值的列表
现在,对于options中的每一行(在外部查询中),我们可以检查id值,看看它是否在子查询返回的列表中
如果我们保证option\u id永远不会为NULL,那么我们可以省略测试“option\u id不为NULL”的谓词。(在更一般的情况下,当一个空值潜入resultset时,外部查询无法判断o.id是否在列表中,并且查询不返回任何行;因此我通常会包括这些行,即使它不是必需的。GROUP BY
也不是严格必需的;尤其是当存在唯一约束(保证唯一性)时在(product_id,option_id)元组上
但是,除了测试之外,不要在(子查询)
中使用,除非
SELECT o.id
, o.name
FROM options o
LEFT
JOIN links k
ON k.option_id = o.id
AND k.product_id = 'foo'
WHERE k.option_id IS NULL
SELECT o.id
, o.name
FROM options o
WHERE NOT EXISTS ( SELECT 1
FROM links k
WHERE k.option_id = o.id
AND k.product_id = 'foo'
)
SELECT o.id
, o.name
FROM options o
WHERE o.id NOT IN ( SELECT k.option_id
FROM links k
WHERE k.product_id = 'foo'
AND k.option_id IS NOT NULL
GROUP BY k.option_id
)