我有一个SQL Server 2008 R2表的子集,如下所示:
cust_id | prod_id | day | price
--------+---------+-----+-------
137656 194528 42373 9.11
137656 194528 42374 9.11
137656 194528 42375 9.61
137656 194528 42376 9.61
137656 194528 42377 9.11
137656 194528 42378 9.11
我需要像这样对不同的价格期间进行排名:
cust_id | prod_id | day | price | rank
--------+---------+-----+-------+------
137656 194528 42373 9.11 1
137656 194528 42374 9.11 1
137656 194528 42375 9.61 2
137656 194528 42376 9.61 2
137656 194528 42377 9.11 3
137656 194528 42378 9.11 3
以便按cust_id
,prod_id
和day
进行排序,但在价格变化时会增加排名。我试图像这样使用DENSE_RANK()
:
SELECT
cust_id, prod_id, [day], price,
DENSE_RANK() OVER (ORDER BY cust_id, prod_id, price)
FROM
@prices
返回类似于:
的内容cust_id | prod_id | day | price | rank
--------+---------+-----+-------+------
137656 194528 42373 9.11 1
137656 194528 42374 9.11 1
137656 194528 42377 9.11 1
137656 194528 42378 9.11 1
137656 194528 42375 9.61 2
137656 194528 42376 9.61 2
显然,从排序中排除这一天会给我这些结果,但每当我按照DENSE_RANK()
部分的顺序列出日期时 - 它只是将每个新的一天划分为新的ID ....
有没有人对如何运作有任何想法?感谢任何建议,如果需要可以提供更多信息
答案 0 :(得分:1)
LAG
和SUM
SELECT
*,
1+SUM(IncCount)OVER(PARTITION BY cust_id ORDER BY [day]) [rank]
--1+SUM(IncCount)OVER(PARTITION BY cust_id ORDER BY [day] ROWS BETWEEN unbounded preceding AND current row) [rank]
FROM
(
SELECT
*,
IIF(LAG(price)OVER(PARTITION BY cust_id ORDER BY [day])<>price,1,0) IncCount
--CASE WHEN LAG(price)OVER(PARTITION BY cust_id ORDER BY [day])<>price THEN 1 ELSE 0 END IncCount
FROM Test
) q
没有LAG
WITH numCTE AS(
SELECT *,ROW_NUMBER()OVER(PARTITION BY cust_id ORDER BY [day]) RowNum
FROM Test
)
SELECT
t1.*,
1+SUM(CASE WHEN t2.price<>t1.price THEN 1 ELSE 0 END)OVER(PARTITION BY t1.cust_id ORDER BY t1.[day]) [rank]
--1+SUM(CASE WHEN t2.price<>t1.price THEN 1 ELSE 0 END)OVER(PARTITION BY t1.cust_id ORDER BY t1.[day] ROWS BETWEEN unbounded preceding AND current row) [rank]
FROM numCTE t1
LEFT JOIN numCTE t2 ON t2.RowNum+1=t1.RowNum AND t2.cust_id=t1.cust_id
具有递归CTE的第三个变体
WITH numCTE AS(
SELECT *,ROW_NUMBER()OVER(PARTITION BY cust_id ORDER BY [day]) RowNum
FROM Test
),
rankCTE AS(
SELECT RowNum,cust_id,prod_id,[day],price,1 [rank]
FROM numCTE
WHERE RowNum=1
UNION ALL
SELECT
n.RowNum,n.cust_id,n.prod_id,n.[day],n.price,
r.[rank]+CASE WHEN n.price<>r.price THEN 1 ELSE 0 END [rank]
FROM numCTE n
JOIN rankCTE r ON n.RowNum=r.RowNum+1 AND n.cust_id=r.cust_id
)
SELECT *
FROM rankCTE
OPTION(MAXRECURSION 0)