【问题标题】:TOP 1 in a inner join doesnt give result expected内部连接中的 TOP 1 没有给出预期的结果
【发布时间】:2016-11-29 20:46:22
【问题描述】:

请帮忙 - 我正在为不应该是一个困难的查询而发疯。 我正在使用 sql server 2012 并希望使用电子邮件地址列出我的客户。

我有一个包含默认电子邮件地址的客户表和一个包含此人的电子邮件地址的联系人表。每个客户可能有多个联系人,也可能没有。联系人可以有多种用途,并且在 ContactDocumentOption 表中针对每种用途都有一个条目。我只对 purposetype = 102 的联系人感兴趣

对于每个客户,我想显示类型 102 联系人的电子邮件地址(如果有多个联系人,则为第一个联系人,或者尽管有任何联系人都可以)。如果没有 102 类联系人,那么我想显示客户的默认电子邮件地址。

除非碰巧是该客户的第一个联系人,否则以下查询不会获取联系人电子邮件,如果客户有两个联系人并且第一个不是 102 类型,则联系人电子邮件为空

SELECT C.Code as Customer
    , C.Name as CustomerName
    , C.Email
    , CC.Email
    , ISNULL(CC.Email, C.Email) as Email 
FROM [dr].[Customer] C 
LEFT OUTER JOIN 
(
    Select TOP 1 CDO.ContactId
        , CustomerId
        , Email 
    from dr.Contact CC 
    INNER JOIN dr.ContactDocumentOption CDO on CDO.ContactId = CC.ContactId 
    where CDO.TransactionTypeId = 102 
    Order by Email
) CC on CC.CustomerId = C.CustomerId 

认为这是因为 TOP 1 在确定它是 102 之前仅获得了最高联系人,因此我将查询更改为以下内容,但结果相同。

SELECT C.Code as Customer
    , C.Name as CustomerName
    , C.Email
    , CC.Email
    , ISNULL(CC.Email, C.Email) as Email 
FROM [dr].[Customer] C 
LEFT OUTER JOIN 
(
    SELECT CustomerId
        , CT.ContactId
        , Email 
    from dr.Contact CT 
    INNER JOIN 
    (
        Select TOP 1 ContactId from dr.ContactDocumentOption 
        where TransactionTypeId = 102
    ) CDO on CDO.ContactId = CT.ContactId
) CC on CC.CustomerId = C.CustomerId

我确实从之前的帖子中获得了一些帮助,但没有任何效果,所以我正在寻求进一步的帮助。谢谢。

【问题讨论】:

  • SELECT TOP 1 会将结果集限制为查询返回的第一条记录。
  • 不要害怕在查询中使用一些空格。那些东西让我的眼睛流血了。
  • 一些相同的数据和所需的输出将大大有助于理解您正在尝试做什么。这是一个很好的起点。 spaghettidba.com/2015/04/24/…

标签: sql-server nested


【解决方案1】:

如果不了解有关表格或数据的更多信息,很难回答这个问题,但这样的事情会让你开始吗?
在一个 cte:
使用 COUNT() OVER() 确定联系人是否具有 102 TransTypeID。
如果没有 TransType 102,请对行进行编号,以便您仅抓取 1 封电子邮件。
然后将具有 TransType 102 的记录与没有的记录合并。

;WITH cte as (
 Select CDO.ContactId,
        CustomerId,
        Email,
        CDO.TransactionTypeId,
        COUNT(CASE WHEN TransactionTypeId = 102 THEN 1 ELSE 0 END) OVER (PARTITION BY Customerid) AS cnt,  
        ROW_NUMBER() OVER(PARTITION BY CustomerId ORDER BY TransactionTypeId ASC) as rn
from dr.Contact CC   
INNER JOIN dr.ContactDocumentOption CDO 
      ON CDO.ContactId = CC.ContactId 
)  
SELECT CDO.ContactId, 
       CustomerId, 
       Email,
       CDO.TransactionTypeId
FROM cte c
WHERE TransactionTypeId = 102 
UNION 
SELECT CDO.ContactId, 
       CustomerId, 
       Email,
       CDO.TransactionTypeId
FROM cte c
WHERE cnt = 0 and rn = 1

【讨论】:

  • top 1 返回与通常由 order by 设置的条件匹配的第一行。在您的第一个示例中,您将获得具有最低电子邮件地址 a,,, 的那个。尝试突出显示内部查询并按 F5 以查看您得到的结果。您可能会感到惊讶。
猜你喜欢
  • 1970-01-01
  • 2018-03-04
  • 2020-05-29
  • 1970-01-01
  • 2019-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-09
相关资源
最近更新 更多