T-SQL分组问题

时间:2016-04-27 19:46:09

标签: sql-server tsql

我有2张桌子。

联系人

ContactID pk
EmailAddress
FirstName
LastName
Address

订单

OrderID pk
ContactID fk

我想获取联系人中每个电子邮件地址的号码或订单,如下所示

select 
    Contacts.EmailAddress,
    count(distinct Orders.OrderID) AS NumOrders
from 
    Contacts inner join Orders on Contacts.ContactID = Orders.ContactID
group by 
    Contacts.EmailAddress

问题是,我还想要名字,姓氏,地址。但我无法按此分组,因为“联系人”中的每个电子邮件地址都可能具有与之关联的不同的名字,姓氏或地址。

即:

myname@email.com,Fred,Jackson,123 Main St
myname@email.com,Bob,Smith,456 Spruce St。

如何更改查询,以便获取该电子邮件地址的“通讯录”中最新条目的名字,姓氏和地址?

提前致谢!

4 个答案:

答案 0 :(得分:0)

试试这个:

select 
    Contacts.Name,
    Contacts.FirstName,
    Contacts.LastName
    Contacts.EmailAddress,
    count(distinct Orders.OrderID) AS NumOrders
from 
    (
        select max(ContactID) as ContactID,
        EmailAddress
        from Contacts 
        group by EmailAddress
    ) MinContactForEachEMailAddress
    inner join 
    Contacts 
    on MinContactForEachEMailAddress.ContactID = Contacts.ContactID
    inner join 
    Orders 
    on Contacts.ContactID = Orders.ContactID
group by 
    Contacts.EmailAddress

答案 1 :(得分:0)

我的第一个想法是使用窗口函数。

SELECT  EmailAddress,
        FirstName,
        Lastname,
        [Address],
        EmailOrderCount
FROM    (SELECT c.EmailAddress,
                c.FirstName,
                c.LastName,
                c.[Address],
                COUNT(o.OrderID) OVER (PARTITION BY c.EmailAddress) EmailOrderCount,
                ROW_NUMBER() OVER (PARTITION BY c.EmailAddress ORDER BY c.ContactID DESC) Rn
        FROM    Contacts c
                JOIN Orders o ON c.ContactID = o.ContactID
        ) t
WHERE Rn = 1

Demo

另一种方法是使用CROSS APPLY将前1个联系人记录附加到摘要行。

SELECT  c.EmailAddress,
        COUNT(o.OrderID) NumOrders,
        ca.FirstName,
        ca.LastName,
        ca.[Address]
FROM    Contacts c
        INNER JOIN Orders ON c.ContactId = o.ContactID
        CROSS APPLY (
            SELECT TOP 1 
                    FirstName,
                    Lastname,
                    [Address]
            FROM    Contacts c2
            WHERE   c2.EmailAddress = c.EmailAddress
            ORDER BY c2.ContactID DESC) ca
GROUP BY c.EmailAddress,
        ca.FirstName,
        ca.LastName,
        ca.[Address]

答案 2 :(得分:0)

一种简单的方法是将原始查询作为子查询并从中进行选择。我做了一些小改动,因为按主键分组比使用电子邮件地址更好。 (可以肯定的是,每个联系人只有一个电子邮件地址,并且基本意图是按人分组吗?)如果是这样,请尝试:

 SELECT DISTINCT c.EmailAddress, c.FirstName, c.LastName, c.Address, sub.NumOrders
 FROM
 (
      select 
          Contacts.ContactID
          count(distinct Orders.OrderID) AS NumOrders
      from 
          Contacts inner join Orders on Contacts.ContactID = Orders.ContactID
      group by 
          Contacts.ContactID
 ) sub
 JOIN Contacts c
 ON sub.ContactID = c.ContactID

如果您确实需要通过电子邮件地址进行分组,请将上述子查询更改为原始查询,并将c.EmailAddress更改为sub.EmailAddress。当然,您可以订购最适合您的SELECT字段。

编辑如下:

ContactID必须是序列号,您可以不断将同一个人放在表格中。因此,如果您在外部查询中添加DISTINCT关键字,我相信它会为您提供所需的内容。

答案 3 :(得分:0)

获得所需内容的另一种方法是使用CTE并使用ROW_NUMBER取“最大”行。

;WITH CTE AS (
    SELECT C.ContactId, C.Name, C.FirstName, C.LastName, C.EmailAddress, 
        ROW_NUMBER() OVER (PARTITION BY EmailAddress ORDER BY ContactId DESC) RowNo
    FROM Contact C 
)
SELECT CTE.*, COUNT(o.OrderID) OVER (PARTITION BY CTE.EmailAddress) Cnt
FROM CTE
    JOIN Orders O on CTE.ContactID = O.ContactID
-- select the "maximum" row
WHERE CTE.RowNo = 1