SQL Server最大n个组查询:最新日期的客户信息

时间:2017-05-03 11:51:47

标签: sql sql-server greatest-n-per-group

Primer:我已经看了几个关于Stack溢出的例子,很多让我接近我需要的但不完全是我需要的东西。请放弃,并且我发现无用的一件事是许多答案已经抛出了一个解决方案,但没有解释它是如何工作的以及为什么需要部件。因此,如果答案可以包括对查询的解释和细分,那将是很好的。谢谢。

问题:我有一个Customer表,如下所示。

Id     Name     Account     Active
1      Bob      ABC         True
2      Jenny    BED         True
3      Tony     POT         False
4      David    DON         False

我还有一张Order表。见下文

OrderId     CustomerId     OrderDate     Status
1           2              2016-04-01    3
2           2              2016-09-05    7
3           2              2017-02-20    5
4           3              2015-02-20    8
5           4              2017-04-16    3

我需要什么:所以我需要一个包含Customer.Id。,Customer.Name,Customer.Account,Customer.Active,Order.Status和最新OrderDate的表,其状态为3或7 。 该表应显示所有客户以及Order.Status和LatestDate的空值,其中客户从未订购过或其订单不符合状态标准。请参阅下面的示例。

CustomerId     Name     Account     Active     Status     LatestDate
1              Bob      ABC         True       NULL       NULL
2              Jenny    BED         True       7          2016-09-05
3              Tony     POT         False      NULL       NULL
4              David    DON         False      3          2017-04-16

因为你可以看到Bob和Tony都有状态和latestDate为null,因为他们要么没有进行交易,要么他们不符合订单状态3或7的标准。大卫只做了有一个订单,所以他的最新简单。 Jenny有多个符合标准的订单和多个订单,所以它接受最新日期的订单并将其添加到我们的表格中(仍考虑状态是3还是7)。

现在在此问题的先前尝试中,我最终将所有交易记入账户(不仅仅是3和7),我已经显示了重复的客户(由于日期不同而无法使用不同的客户) ,并在另一次尝试中获取所有数据但忽略了任何具有空值的东西。如前所述,我已经看到很多关于堆栈溢出的例子,但它们似乎都给我的问题提出了问题,并且没有为我提供足够的解释或细分,以便能够根据我的原因修改它。

因此,如果有人可以提供此问题的解决方案以及SQL的细分,只是为了我的清晰理解(以及其他人的理解)。提前谢谢。

我最近的尝试是:

Select Distinct c.Id, c.[Name], c.Account, c.Active, o.Status, 
LatestDates.LatestDate
From Customer as c
Left Outer Join
(Select CustomerId, Max(OrderDate) LatestDate From [Order] Group By 
CustomerId) LatestDates On c.Id = LatestDates.CustomerId
Left Join [Order] o on LatestDates.CustomerId = o.CustomerId and 
LatestDates.LatestDate = o.OrderDate
Where c.Active is not null
Order by c.Active

然而,这个解决方案没有考虑到3和7检查,我不明白它足以确认我得到的数据是正确的。这是从不同的堆栈溢出问题中获取的。如果您需要更多详细信息,请与我们联系。

2 个答案:

答案 0 :(得分:1)

只需使用row_number()

select c.*, o.status, o.latestdate
from Customer c left join
     (select o.*,
             row_number() over (partition by o.customerId order by o.orderDate desc) as seqnum
      from orders o
     ) o
     on o.customerId = c.customerId
where seqnum = 1 and c.Active is not null
order by c.Active;

答案 1 :(得分:0)

top with tiesrow_number()

一起使用
select top 1 with ties
    c.Id, c.[Name], c.Account, c.Active, o.Status, o.OrderDate
from Customer as c
  left join [Order] o
    on c.Id= o.CustomerId
   and o.Status in (3,7)
where c.Active is not null
order by row_number() over (partition by c.Id order by o.OrderDate desc)

outer apply()

select 
  c.Id, c.[Name], c.Account, c.Active, o.Status, o.OrderDate
from Customer as c
  outer apply (
    select top 1
      i.Status, i.OrderDate
    from [Order] i
    where i.CustomerId = c.Id
      and i.Status in (3,7)
    order by i.OrderDate desc
  ) as o

或通过在派生表查询中包含status条件来调整查询尝试:

Select Distinct c.Id, c.[Name], c.Account, c.Active, o.Status, LatestDates.LatestDate
From Customer as c
  Left Outer Join (
      Select CustomerId, Max(OrderDate) as LatestDate 
      From [Order] i
      where i.Status in (3,7)
      Group By CustomerId
      ) LatestDates On c.Id = LatestDates.CustomerId
  Left Join [Order] o 
    on LatestDates.CustomerId = o.CustomerId 
   and LatestDates.LatestDate = o.OrderDate
   and o.Status in (3,7)
Where c.Active is not null
Order by c.Active

所有3的rextester演示:http://rextester.com/WNVKL52324

全部3回归:

+----+-------+---------+--------+--------+------------+
| Id | Name  | Account | Active | Status | LatestDate |
+----+-------+---------+--------+--------+------------+
|  1 | Bob   | ABC     | True   | NULL   | NULL       |
|  2 | Jenny | BED     | True   | 7      | 2016-09-05 |
|  3 | Tony  | POT     | False  | NULL   | NULL       |
|  4 | David | DON     | False  | 3      | 2017-04-16 |
+----+-------+---------+--------+--------+------------+