2015-07-14 40 views
9

W PostgreSQL 9.4 funkcje okna mają nową opcję FILTER do wyboru podzbioru ramki okna do przetwarzania. Dokumentacja wspomina o tym, ale nie dostarcza próbki. Wyszukiwanie online dostarcza niektórych próbek, w tym z 2ndQuadrant, ale wszystkie znalezione przykłady są dość trywialne i mają stałe wyrażenia. To, czego szukam, to wyrażenie filtru, które zawiera wartość bieżącego wiersza.Odwoływanie się do bieżącego wiersza w klauzuli FILTER o funkcji okna

Załóżmy Mam tabeli z wieloma kolumnami, z których jeden jest date typu:

col1 | col2 |  dt 
------------------------ 
    1 | a | 2015-07-01 
    2 | b | 2015-07-03 
    3 | c | 2015-07-10 
    4 | d | 2015-07-11 
    5 | e | 2015-07-11 
    6 | f | 2015-07-13 
...

definicja okno do przetwarzania na date na całej tabeli jest trywialnie skonstruowanej: WINDOW win AS (ORDER BY dt)

Interesuje mnie wiedzieć, ile wierszy jest obecnych w, powiedzmy, 4 dni przed bieżącym wierszem (włącznie). Więc chcę wygenerować ten wynik:

col1 | col2 |  dt  | count 
-------------------------------- 
    1 | a | 2015-07-01 | 1 
    2 | b | 2015-07-03 | 2 
    3 | c | 2015-07-10 | 1 
    4 | d | 2015-07-11 | 3 
    5 | e | 2015-07-11 | 3 
    6 | f | 2015-07-13 | 4 
...

FILTER klauzula funkcji okna wydaje się oczywistym wyborem:

count(*) FILTER (WHERE current_row.dt - dt <= 4) OVER win

Ale jak mogę określić current_row.dt (dla braku lepszego składni)? Czy to możliwe?

Jeśli nie jest to możliwe, czy istnieją inne sposoby wybierania zakresów date w ramce okna? Specyfikacja ramek nie jest pomocna, ponieważ jest ona oparta na wierszach.

Nie interesują mnie alternatywne rozwiązania z wykorzystaniem pod-zapytań, musi to być oparte na przetwarzaniu okien.

+0

Interesujący problem. Jako regularny Postgres powinieneś wiedzieć, aby podać definicję tabeli (lub jeszcze lepiej, kompletny skrypt "STWÓRZ TABELĘ"). –

+0

@ErwinBrandstetter Czy jest to coś, co zasługuje na oflagowanie jako "żądanie funkcji"? Dla mnie wydaje się bardzo cenne, aby móc filtrować ramę okna na podstawie pewnych warunków obecnych w bieżącym wierszu. – Patrick

+0

Tak, przydałoby się to w przypadku różnych problemów, widziałem tutaj kilka powiązanych pytań na stronie SO. Obawiam się, że funkcja wymagałaby dużo pracy z powodu głównych zmian w implementacji, ale nie zaszkodzi udokumentować zainteresowanie publiczne tą funkcją. Wygląda na to, że brakuje funkcji 'RANGE MIĘDZY ... PRECEDING/FOLLOWING', która już jest [udokumentowana w Wiki ToDo] (https://wiki.postgresql.org/wiki/Todo#Window_Functions) –

Odpowiedz

5

Nie jesteś w rzeczywistości agregująca wierszy, więc nowa klauzula agregująca FILTER nie jest właściwym narzędziem. Funkcja okna jest bardziej podobna, problem pozostaje jednak: okno nie może zależeć od wartości bieżącego rzędu. Może on liczyć tylko określoną liczbę wierszy poprzedzających lub następujących z klauzulą ​​ROWS.

Aby to wykonać, łączna liczba dziennych i LEFT JOIN do pełnego zestawu dni w zakresie. Następnie można zastosować funkcję okna:

SELECT t.*, ct.ct_last4days 
FROM (
    SELECT *, sum(ct) OVER (ORDER BY dt ROWS 3 PRECEDING) AS ct_last4days 
    FROM (
     SELECT generate_series(min(dt), max(dt), interval '1 day')::date AS dt 
     FROM tbl t1 
    ) d 
    LEFT JOIN (SELECT dt, count(*) AS ct FROM tbl GROUP BY 1) t USING (dt) 
    ) ct 
JOIN tbl t USING (dt); 

pomijając ORDER BY dt w definicji ramki wdowa zwykle roboty, ponieważ zamówienie jest przeniesione z generate_series() w podzapytania. Ale nie ma żadnych gwarancji w standardzie SQL bez wyraźnego ORDER BY i może on łamać bardziej złożone zapytania.

SQL Fiddle.

pokrewne:

+0

Kiedy klauzula" FILTER " stosuje się do funkcji agregujących w obecności klauzuli "OVER", które [* działają jak funkcje okna (...) w przeciwnym razie działają jak zwykłe agregaty *] (http://www.postgresql.org/docs/current/static/ functions-window.html), aby unieważnić zdanie otwierające, jeśli dobrze rozumiem zarówno dokumentację, jak i ciebie. Zaakceptowany za bycie pracującym rozwiązaniem i skrupulatną dbałością o szczegóły, ale tylko niechętnie, więc za zależność od pod-zapytań, za które oczywiście nie można winić. – Patrick

+0

@Patrick: Funkcje agregujące (można) zwijają wiersze, podczas gdy funkcje okna nie. Oczywiście nie chcesz składać wierszy, więc jesteś w sferze funkcji okna. Klauzula 'FILTER' implementuje niektóre funkcje funkcji okna dla funkcji agregujących, ale i tak potrzebujesz funkcji okna. –

1

Nie sądzę, nie ma żadnych składni, które oznacza "bieżący wiersz" w wyrażeniu . Plik gram.y dla postgrera sprawia, że ​​klauzula filtru przyjmuje tylko a_expr, która jest po prostu normalną klauzulą ​​wyrażenia. Tam nie jest niczym szczególnym dla funkcji okna lub klauzul filtru w wyrażeniu. O ile mogę znaleźć, jedynym bieżącym pojęciem wiersza w klauzuli window jest określenie granic ramki okna. Nie sądzę, że to ci pomoże , czego chcesz.

Jest możliwe, że można dostać jakąś trakcję z otaczającej zapytania:

http://www.postgresql.org/docs/current/static/sql-expressions.html

Kiedy pojawi się łączna ekspresja w podkwerendzie (patrz punkt 4.2.11 oraz sekcja 9.22), łączna jest zwykle oceniany w wierszach podzapytania. Ale wyjątek występuje, jeśli argumenty agregatu (i filter_clause, jeśli istnieją) zawierają tylko zmienne z zewnętrznego poziomu: agregacja należy wtedy do najbliższego takiego zewnętrznego poziomu, i jest obliczana na podstawie wierszy tego zapytania.

ale nie jest to dla mnie oczywiste.