如何在左连接中选择单个记录
Posted
技术标签:
【中文标题】如何在左连接中选择单个记录【英文标题】:How to select a single record in a left join 【发布时间】:2011-09-09 15:24:19 【问题描述】:我需要使用其键 ModelID 从模型表中选择一个特定模型。我还需要从 Model_Content 表中添加内容简介。然而,Models_Content 表对每个模型都有几个内容简介。我只需要选择第一个简介。
我的表格如下所示:
Models // table
ModelID // pk
Model // varchar
Models_Content // table
ContentID // pk
ModelID // fk
Content // varchar
SELECT M.ModelID, M.Model, C.Content
FROM Models M LEFT JOIN Models_Content C ON M.ModelID = C.ModelID
WHERE M.ModelID = 5
如何调整我的查询以仅选择特定模型的第一个内容简介?
【问题讨论】:
“第一”是最低的ContentID
?
@Martin,是的。最低的 ContentID 将是我想要的。
【参考方案1】:
SELECT
M.ModelID, M.Model, C.Content
FROM
Models M
LEFT JOIN
Models_Content C
ON C.ContentID = (SELECT MIN(ContentID) FROM Models_Content WHERE ModelID = M.ModelID)
WHERE
M.ModelID = 5
或者
;WITH sorted_content AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY ModelID ORDER BY ContentID) AS itemID,
*
FROM
Models_Content
)
SELECT
M.ModelID, M.Model, C.Content
FROM
Models M
LEFT JOIN
sorted_content C
ON C.ModelID = M.ModelID
AND C.itemID = 1
WHERE
M.ModelID = 5
【讨论】:
我没有尝试您的最佳解决方案,但它看起来非常简单。我明白了。谢谢! 其实,你的解决方案正是我需要的。我绝对想返回多个模型,每个模型都有一个内容简介。另一个查询使用 TOP 1,所以它只返回一个模型,这不是我想要的。 cte 解决方案很好,恕我直言,当 'Models_Content' 表没有自己的主键 id 字段并且没有额外的子查询发生时,因为它可以工作 很遗憾,200k表太慢了,完全不可能 @vladkras 然后你需要适当的索引。比如Models_Content上(ModelID, ContentId)
的复合索引。【参考方案2】:
肖恩的回答是最好的具体解决方案,但只是添加另一个“通用”解决方案
SELECT M.ModelID,
M.Model,
C.Content
FROM Models M
OUTER APPLY (SELECT TOP 1 *
FROM Models_Content C
WHERE M.ModelID = C.ModelID
ORDER BY C.ContentID ASC) C
WHERE M.ModelID = 5
【讨论】:
+1 :我已经有一段时间没有使用 MS SQL Server 了。我总是忘记我有多喜欢使用 APPLY :) [哦,我是个极客...] 我从来没有用过APPLY,但看起来很简单。我会记住这个解决方案。谢谢! @Evik -OUTER APPLY
有点 RBAR,但如果您在 Models_Content
中有许多特定模型的项目,它会更有效。此类查询的通用名称是“Greatest n per group”。 Itzik Ben Gan discusses some approaches here
@Martin SMith - 肯定是APPLY
的 RBARness (我今天编的词比我想数的多) 取决于查询?我经常看到应用内联表值函数非常有效的情况。【参考方案3】:
SELECT TOP 1 M.ModelID, M.Model, C.Content
FROM Models M LEFT JOIN Models_Content C ON M.ModelID = C.ModelID
WHERE M.ModelID = 5
ORDER BY C.ContentID ASC
【讨论】:
使用TOP 1
可以很好地与当前的 WHERE 子句配合使用,但不能同时推广到多个模型。
我发现 TOP 1 并没有给我想要的东西。我没有提到我需要检索多个模型,每个模型只有一个内容简介。不过,您的回答很有帮助。谢谢!【参考方案4】:
将您的 JOIN
更改为:
LEFT JOIN (SELECT ModelID, MAX(Content) as Content FROM Models_Content GROUP BY ModelID)
这是假设你不在乎你得到哪个Content
。
【讨论】:
实际上,我确实关心我得到哪些内容。我应该在问题中说清楚。不过感谢您的回答!【参考方案5】:您可以选择MIN ( contentID )
【讨论】:
【参考方案6】:这可能是 Randy 答案的扩展,但我并不完全清楚。
出于性能原因,我想尽量减少查询中SELECT
语句的数量,因此我在主选择中使用MIN
语句,而不是在JOIN
中:
SELECT
table_1.id AS id,
table_1.name AS name,
MIN(table_2.id) AS table_2_id
FROM table_1
LEFT JOIN table_2 ON table_2.table_1_id = table_1.id
-- additional JOINs and WHERE excluded
GROUP BY table_1.id, table_1.name
LIMIT 5
可能会根据数据总量进行权衡。身份证。我的查询需要从删除几个步骤的条件中挖掘数据。
【讨论】:
【参考方案7】:我不知道如何直接在 SQL Server 上进行,但如果您使用 Azure 访问 SQL Server,您可以使用 U-SQL,它允许您使用 ANY_VALUE
。它将从连接表的随机行中返回一个值。
SELECT M.ModelID, M.Model, ANY_VALUE(C.Content)
FROM Models M
LEFT JOIN Models_Content C ON M.ModelID = C.ModelID
WHERE M.ModelID = 5
或者,如果所有型号都需要它
SELECT M.ModelID, M.Model, ANY_VALUE(C.Content)
FROM Models M
LEFT JOIN Models_Content C ON M.ModelID = C.ModelID
更多信息:https://docs.microsoft.com/en-us/u-sql/functions/aggregate/any-value
【讨论】:
mysql 对 SQL Server 问题的回答? @MatBailie 我错过了 sql-server 标签。谢谢,我会修复答案,请稍等!【参考方案8】:SELECT M.ModelID
, M.Model
, (SELECT TOP 1 Content
FROM Models_Content
WHERE ModelID = M.ModelID
ORDER BY ContentId ASC) as Content
FROM Models M
WHERE M.ModelID = 5
【讨论】:
这甚至不会解析,因为Content
字段不在您的子查询中。
哦,来吧,如果 Models_Content 的 TOP 1 是错误的模型怎么办!?
我更新了那个,谢谢。但我认为我不应该为此投反对票
@Meen - 那你错了。错误的答案会被否决,这就是它的工作原理。而且您的编辑并不正确,请参阅 Dems 的评论
@Meenaksi - 您正在从 Model_Content 在加入 ModelID 之前选择第一条记录。这意味着您可以(很可能会)随机选择一条不适合指定模型的记录,因此根本不会获得任何数据。 即使那里确实有合法记录。以上是关于如何在左连接中选择单个记录的主要内容,如果未能解决你的问题,请参考以下文章
C# SQL 在左连接中选择右表只返回唯一值,而不是每个值的一个实例