SQL: ostatnia wartość () zwraca zły wynik (ale pierwsza wartość () działa dobrze)
Mam tabelę w SQL Server 2012 Jak pokazuje migawka:
Następnie używam last_value () i First Value, aby uzyskać średnią ilość każdego EmpID dla różnych lat. Skrypt wygląda następująco:
SELECT A.EmpID,
First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '200901AvgAmount',
Last_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '201112AvgAmount'
FROM Emp_Amt AS A
Jednak wynik dla tego zapytania to:
W kolumnie "201112avgamount" pokazuje różne wartości dla każdego EmpID, podczas gdy "200901avgamount" ma prawidłowe wartości.
Czy jest coś nie tak z moim skryptem SQL? Zrobiłem wiele badań online, ale nadal nie mogę znaleźć odpowiedzi....
3 answers
Nie ma nic złego w Twoim skrypcie, tak działa partycjonowanie w SQL server :/. Jeśli zmienisz wartość LAST_VALUE na MAX wynik będzie taki sam. Rozwiązaniem byłoby:
SELECT A.EmpID,
First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '200901AvgAmount',
Last_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS '201112AvgAmount'
FROM Emp_Amt AS A
Jest świetny post o tym, link . GL!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-13 16:11:49
Oto szybkie zapytanie, aby zilustrować zachowanie:
select
v,
-- FIRST_VALUE() and LAST_VALUE()
first_value(v) over(order by v) f1,
first_value(v) over(order by v rows between unbounded preceding and current row) f2,
first_value(v) over(order by v rows between unbounded preceding and unbounded following) f3,
last_value (v) over(order by v) l1,
last_value (v) over(order by v rows between unbounded preceding and current row) l2,
last_value (v) over(order by v rows between unbounded preceding and unbounded following) l3,
-- For completeness' sake, let's also compare the above with MAX()
max (v) over() m1,
max (v) over(order by v) m2,
max (v) over(order by v rows between unbounded preceding and current row) m3,
max (v) over(order by v rows between unbounded preceding and unbounded following) m4
from (values(1),(2),(3),(4)) t(v)
Wyjście powyższego zapytania można zobaczyć tutaj ( sqlfiddle tutaj):
| V | F1 | F2 | F3 | L1 | L2 | L3 | M1 | M2 | M3 | M4 |
|---|----|----|----|----|----|----|----|----|----|----|
| 1 | 1 | 1 | 1 | 1 | 1 | 4 | 4 | 1 | 1 | 4 |
| 2 | 1 | 1 | 1 | 2 | 2 | 4 | 4 | 2 | 2 | 4 |
| 3 | 1 | 1 | 1 | 3 | 3 | 4 | 4 | 3 | 3 | 4 |
| 4 | 1 | 1 | 1 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
Niewiele osób myśli o niejawnych ramkach, które są stosowane do funkcji okien, które przyjmują klauzulę ORDER BY
. W tym przypadku okna są domyślne do ramki RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. (Zakres nie jest dokładnie taki sam jak wiersze, ale to już inna historia). Pomyśl o tym w ten sposób:
- w rzędzie z
v = 1
uporządkowaną ramką okna spansv IN (1)
- w wierszu z
v = 2
ramka okna uporządkowanego rozciąga sięv IN (1, 2)
- w wierszu z
v = 3
rama okna uporządkowanego rozciąga sięv IN (1, 2, 3)
- w wierszu z
v = 4
rama okna uporządkowanego rozciąga sięv IN (1, 2, 3, 4)
Jeśli chcesz zapobiec takiemu zachowaniu, masz dwie opcje:
- użyj jawnej klauzuli
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
dla uporządkowanych funkcji okien - użyj klauzuli
ORDER BY
w tych funkcjach okien, które pozwalają na ich pominięcie (jakoMAX(v) OVER()
)
Więcej szczegółów znajdziesz w tym artykule o LEAD()
, LAG()
, FIRST_VALUE()
oraz LAST_VALUE()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-23 16:37:48
Najprostszym sposobem jest powtórzenie zapytania za pomocą first_value, po prostu zrób porządek jako asc dla 1. przypadku i desc dla 2. przypadku.
SELECT A.EmpID,
First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '200901AvgAmount',
First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey desc) AS '201112AvgAmount'
FROM Emp_Amt AS A
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-24 13:14:12