Wpis z mikrobloga

Jeszcze nie guglałem stackoverflow jak to zrobić, może ktoś stąd wie. Mam nietrywialny problem. Nie wiem jak zrobić laga (poprzedni wiersz) w partition by albo jakoś inaczej, ale tak by lag ignorował warunek where? SQL Server.

Mam sobie tabelę faktów która jest logiem zamówień z systemu. Każde zamówienia może mieć 1 lub więcej wersji. Wersja się zmienia gdy w zamówieniu zostanie zmieniona kwota (w uproszczeniu). Np. zamówienie było najpierw z kwotą 100, ktoś je zmienił na 30, to w tabeli będę miał dwa wiersze. Version = 1, Amount = 100 i Version = 2, Amount = 30. Moim celem jest policzenie delty czyli o ile spadła/wzrosła kwota. Ostatecznia suma delty dla każdego ID ma dawać amount ostatniej wersji. Przykład na obrazku.

No więc liczę sobie ten Delta Amount poprzez [Amount] - LAG([Amount], 1, 0) OVER (PARTITION BY [ID] ORDER BY [Version])
I wszystko działa i mam dane tak jak chcę.

Ale rozważmy taki scenariusz: ładowanie przyrostowe. Dane ładuje dziennie, biorę max z wartości timestamp i ładuje wiersze tylko większe od max(timestamp) żeby załadować nowe wiersze. Bo stare się nie zmieniają. No, ale tą kalkulację muszę niestety robić po całości.
A chciałbym robić w tym przypadku WHERE dla timestamp > 11, ale tak by nowe wersje np. dla ID = 1, miały dostęp do ostatniej wartości czyli do do Amount = 50 w Version = 3. Jak wiadomo w zwykłym where to nie zadziała bo dane są ucięte przez warunek timestamp = 11. Czyli nowy wiersz nie ma dostępu do wierszy poprzednich gdzie timestamp jest mniejszy niż te 11.

No czyli chciałbym robić to co robię, ale bez jechania partition by po całości. Jak to zrobić? Kursorem (nigdy nie używałem)? Jakieś temp table? Chodzi mi o jak najlepszy performance.

#sql #sqlserver
Pobierz przecietnyczlowiek - Jeszcze nie guglałem stackoverflow jak to zrobić, może ktoś stąd...
źródło: comment_1647970842jjDPC0ERvEYfrejDvwUrFS.jpg
  • 2
via Wykop Mobilny (Android)
  • 1
@przecietnyczlowiek: CTE z * i ROW_NUMBER PARTITION BY Id ORDER BY Version DESC ze tabeli docelowej (target), potem zapytanie
SELECT * FROM source WHERE Timestamp > (SELECT MAX(timestamp) FROM target)
UNION ALL
SELECT * FROM CTE WHERE rn = 1
I na tym zapytaniu (może być jako drugie CTE) robisz sobie swoje obliczenia LAG

Indeks dla ROW_NUMBER według zasady POC może pomóc (partition -> ordering -> covering)

O ile dobrze zrozumiałem