如何在左连接中选择单个记录

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 在左连接中选择右表只返回唯一值,而不是每个值的一个实例

在左连接中选择取决于另一个表中字段总和的行?

教义 2,如何在左连接结果集中获取属性? [关闭]

在左连接中使用 Oracle rank()

实体框架在左连接时强制内连接使用 DefaultIfEmpty() 语法

SQL Server:在左连接查询的执行计划中插入隐藏的“排序”