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]