2017-11-20 120 views
5

Mam podzbiór R2 tabeli SQL Server 2008 jak poniżej:Tabela rankingowa na jednej kolumnie podczas sortowania na innej

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 

muszę uporządkować różne okresy cena tak:

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 

, aby sortować według cust_id, prod_id i day rosnąco, ale zwiększa jej pozycję, gdy cena się zmieni. Próbowałem użyć DENSE_RANK() takiego:

SELECT 
    cust_id, prod_id, [day], price, 
    DENSE_RANK() OVER (ORDER BY cust_id, prod_id, price) 
FROM 
    @prices 

ta zwraca coś takiego:

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 

Oczywiście wyłączając dzień od rodzaju dadzą mi te wyniki, ale ilekroć to dzień w kolejności od sekcja DENSE_RANK() - to po prostu rozdziela każdy nowy dzień jako nowy ID ...

Czy ktoś ma jakieś pomysły na to, jak to powinno działać? Wdzięczni za wszelkie rady i może dać więcej informacji, jeśli wymagane

+0

Tak jak w notatce, próbowałem użyć [różnica w metoda numeru wiersza] (http://rextester.com/COMB14371), ale nie udało się, więc prawdopodobnie nie jest to dobre podejście. –

+0

jaka będzie pozycja po zmianie identyfikatora cust_id lub prod_id? byłoby lepiej, gdyby dodać to również w swojej próbce. –

Odpowiedz

1

Pierwszy wariant z LAG i 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 

Drugi wariant bez 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 

wariantu trzeciego z rekurencyjnej 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) 
+0

Dzięki temu, wygląda na to, że zadziała, ale niestety LAG nie działa na bazie danych sql 2008 R2, powinienem był o tym wspomnieć w początkowym pytaniu, zaktualizowałem je teraz - przepraszam! – samil90

+0

Wypróbuj drugi wariant. Mam nadzieję, że działa w SQLServer 2008. – Leran2002

+0

Dzięki Leran, przetestowałem obie te opcje. Opcja 2 daje mi 2 za pierwszy rząd nowej ceny, ale potem wraca z powrotem do 1 - co utrudnia grupowanie według tego identyfikatora i uzyskanie minimalnego i maksymalnego dnia, aby podać przedział cenowy. Opcja 3 jest lepsza, ponieważ daje mi przyrostową rangę dla każdej nowej ceny, ale nie uwzględnia różnych cust_ids. – samil90

Powiązane problemy