Sql 从组记录中选择前N名

Sql 从组记录中选择前N名,sql,sql-server,Sql,Sql Server,当价格改变时,我需要列出第一条记录。使用下面的例子 发票表记录按客户分组并按价格和日期排序 Index Customer Date Price 01 A May-01-2016 $12.00 02 A May-11-2016 $12.00 03 A May-21-2016 $13.00 04 A May-22-2016 $13.00 05 A May-23-2

当价格改变时,我需要列出第一条记录。使用下面的例子

发票表记录按客户分组并按价格和日期排序

Index  Customer Date         Price
01     A        May-01-2016  $12.00
02     A        May-11-2016  $12.00

03     A        May-21-2016  $13.00
04     A        May-22-2016  $13.00
05     A        May-23-2016  $13.00
06     A        May-24-2016  $13.00

07     A        Jun-01-2016  $14.00
08     A        Jun-11-2016  $14.00
09     A        Jun-21-2016  $14.00
10     A        Jun-25-2016  $14.00

11     B        May-02-2016  $12.50
12     B        May-12-2016  $12.50

13     B        May-22-2016  $13.50

14     B        May-24-2016  $13.80
15     B        May-26-2016  $13.80
16     B        May-28-2016  $13.80

17     B        Jun-02-2016  $14.60
18     B        Jun-12-2016  $14.60
19     B        Jun-22-2016  $14.60
20     B        Jun-26-2016  $14.60
当价格改变时,我需要得到第一张记录。结果将是:

01     A        May-01-2016  $12.00

03     A        May-21-2016  $13.00

07     A        Jun-01-2016  $14.00

11     B        May-02-2016  $12.50

13     B        May-22-2016  $13.50

14     B        May-24-2016  $13.80

17     B        Jun-02-2016  $14.60
03     A        May-21-2016  $13.00

07     A        Jun-01-2016  $14.00

14     B        May-24-2016  $13.80

17     B        Jun-02-2016  $14.60
除此之外,我是否可以将结果限制为每个客户的最新2条记录?结果将是:

01     A        May-01-2016  $12.00

03     A        May-21-2016  $13.00

07     A        Jun-01-2016  $14.00

11     B        May-02-2016  $12.50

13     B        May-22-2016  $13.50

14     B        May-24-2016  $13.80

17     B        Jun-02-2016  $14.60
03     A        May-21-2016  $13.00

07     A        Jun-01-2016  $14.00

14     B        May-24-2016  $13.80

17     B        Jun-02-2016  $14.60
谢谢。

第一部分:

SELECT id, customer, dte, price
  FROM (SELECT id, customer, dte, price
              ,COALESCE(LAG(price) OVER(PARTITION BY customer ORDER BY id), price - 1) AS prev_price
          FROM invoice) x
  WHERE x.price <> x.prev_price
  ORDER BY x.id
第二部分:

SELECT id, customer, dte, price
  FROM (SELECT id, customer, dte, price
              ,ROW_NUMBER() OVER (PARTITION BY customer ORDER BY id DESC) AS row_num
          FROM (SELECT id, customer, dte, price
                      ,COALESCE(LAG(price) OVER (PARTITION BY customer ORDER BY id), price - 1) AS prev_price
                  FROM invoice) x
          WHERE x.price <> x.prev_price) y
  WHERE row_num <= 2
  ORDER BY id
结果集
假设date列采用某种有效的dateformat,否则您应该对其进行转换,下面是另一种方法:

;with cte as (
    select 
       Invoice.[index], Invoice.Customer, Invoice.Date, Invoice.Price, 
       rn = row_number() over (partition by Invoice.customer order by date desc) 
    from Invoice
    join (
       select Customer, price, min(date) min_date 
       from Invoice 
       group by Customer, price
    ) t1 on Invoice.Customer = t1.Customer and Invoice.Date = t1.min_date
)
select [index], Customer, date, price 
from cte where rn <= 2 order by [index]
如果您使用的是SQL Server 2012+,则可以使用窗口聚合函数并执行此查询,该查询可能更有效,也可能更无效:

select [index], Customer, date, price 
from (
    select *, rn = dense_rank() over (partition by customer order by min_date desc) 
    from (select *, min(date) over (partition by customer, price) min_date from Invoice) a
) b where rn <= 2 and Date = min_date order by [index]

对我来说,lag似乎是最好的解决方案。如果lag函数可用,确实是一个很好的解决方案。如果它是Access sql,它将是什么?@YellowLarry Access没有任何窗口函数,因此您必须创造性地使用多个嵌套查询,或者在VBA中执行。您使用的sql Server的具体版本是什么?某些窗口功能需要2012+
select [index], Customer, date, price 
from (
    select *, rn = dense_rank() over (partition by customer order by min_date desc) 
    from (select *, min(date) over (partition by customer, price) min_date from Invoice) a
) b where rn <= 2 and Date = min_date order by [index]