【问题标题】:SQL to pick only one record in one-to-many relationshipSQL在一对多关系中只选择一条记录
【发布时间】:2017-05-02 17:37:59
【问题描述】:

在当前/潜在客户的以下查询中,我需要显示 CustomerID、Customer's LastName,以及显示客户是否下过at least 一个订单的列。 但是,正如预期的那样,如果客户下了多个订单(一对多关系),它会显示客户的多条记录。 问题:我们只需要报告一个客户是否下过至少一个订单,如何在此处只显示每个客户的一条记录?

SELECT c.customerID, o.OrderID, CASE When ISNULL(o.OrderID, 0) = 0 Then 0 Else 
1 End as YesNO
FROM Customers c
LEFT JOIN Orders o
 ON c.customerID = o.customerID

【问题讨论】:

  • 为什么不使用 CASE 语句而不是使用计数来检查订单数是否大于或等于 1
  • SELECT c.customerID, min(o.OrderID), case when coalesce(count(o.orderID),0) >0 then 1 else 0 end from ... group by c.customerID, o.OrderID
  • @xQbert 将返回多行,因为您仍在按 o.OrderId... 分组,使用 min(o.OrderID)(或 max())可以解决此问题。
  • @sqlzim...这是真的...SELECT c.customerID, min(o.OrderID), case when coalesce(count(o.orderID),0) >0 then 1 else 0 end from ... group by c.customerID 并从 group by 中删除 o.orderId!
  • “问题:我们如何只在此处显示每个客户的一条记录,因为我们只需要报告客户是否至少下了一个订单?”表示您不需要返回OrderId,只需返回YesNo

标签: sql sql-server tsql sql-server-2012 left-join


【解决方案1】:

使用outer apply()

select 
    c.customerID
  , o.OrderID
  , case when o.OrderID is null then 0 else 1 end as YesNO
from Customers c
  outer apply (
    select top 1 o.OrderID
    from Orders o
    where c.customerID = o.customerID
  ) o

您也可以使用o.OrderId is null 代替ISNULL(o.OrderID, 0) = 0


使用group bymin()

select 
    c.customerID
  , min(o.OrderID) as OrderId
  , case when min(o.OrderID) is null then 0 else 1 end as YesNO
from Customers c
  left join Orders o 
    on c.customerID = o.customerID 
group by c.CustomerID  

【讨论】:

  • 感谢您和 SO 创始人及其团队在全球传播知识。这就像人们问:我可以帮助你,我可以伸出援助之手吗?注意:o.OrderId is null instead of ISNULL(o.OrderID, 0) = 0 可能无法按照here 的解释工作。
  • @nam 您之前链接到的有关null 的问题的答案不正确。这是一个简单的例子:rextester.com/NCJR80179
  • 但是在post 示例中使用o.OrderId is null 总是给我1,无论o.OrderID 是否为空。我认为使用o.OrderId is null 可能在OUTER Join 的情况下不起作用。我认为SQL编译器可能假设o.OrderID是一个PK是not null。当不使用此 SO 帖子 example 中的 OUTER Join 时,这可能会起作用。
  • @nam 我相信is null 的问题存在不同的根本原因,因为您描述的结果不适合这种情况。您尚未提供 MVE stackoverflow.com/help/mcve
【解决方案2】:

使用分组依据。

SELECT c.customerID, o.OrderID, CASE When ISNULL(o.OrderID, 0) = 0 Then 0 Else 1 End as YesNOFROM Customers cLEFT JOIN Orders o ON c.customerID = o.customerID GROUP BY c.customerID

【讨论】:

  • 关闭,但不能解决每个客户的多条记录问题。通常,如果存在重复,我们不会在没有聚合的情况下进行分组,否则会更有意义。并且在 sql server group by 中必须包含所有非聚合列,这与 mySQL 不同。
【解决方案3】:

如果您的问题中的描述可信,即您想知道客户是否已下订单,但不需要为每个客户提供代表OrderId

select C.CustomerId,
  case when exists ( select 42 from Orders as O where O.CustomerId = C.CustomerId )
    then 1 else 0 end as YesNo
  from Customers as C;

请注意,当您不需要确切的数字时,existscount 更有效。

【讨论】:

    猜你喜欢
    • 2011-01-07
    • 2014-06-30
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多