Mam tabelę z takimi liczbami (status jest BEZPŁATNY lub PRZYPISANY)
status numeru id_set ----------------------- 1 000001 PRZYPISANY 1 000002 ZA DARMO 1 000003 PRZYPISANE 1 000004 ZA DARMO 1 000005 ZA DARMO 1 000006 PRZYPISANY 1 000007 PRZYPISANY 1 000008 ZA DARMO 1 000009 ZA DARMO 1 000010 ZA DARMO 1 000011 PRZYPISANY 1 000012 PRZYPISANY 1 000013 PRZYPISANY 1 000014 ZA DARMO 1 000015 PRZYPISANY
i muszę znaleźć „n” kolejne liczby, więc dla n = 3 zapytanie zwróci
1 000008 ZA DARMO 1 000009 ZA DARMO 1 000010 ZA DARMO
Powinien zwracać tylko pierwszą możliwą grupę każdego zestawu id_set (w rzeczywistości byłby wykonywany tylko dla zestawu id_set na zapytanie)
Sprawdzałem funkcje WINDOW, próbowałem zapytań COUNT(id_number) OVER (PARTITION BY id_set ROWS UNBOUNDED PRECEDING)
, ale to wszystko, co mam :) Nie mogłem wymyślić logiki, jak to zrobić w Postgresie.
Myślałem o stworzeniu wirtualnej kolumny za pomocą funkcji WINDOW, zliczającej poprzednie wiersze dla każdej liczby, gdzie status = „FREE”, a następnie wybierz pierwszą liczbę, gdzie liczba jest równa mojej „n”.
A może grupuj numery według statusu, ale tylko od jednego PRZYPISANEGO do innego PRZYPISANEGO i wybierz tylko grupy zawierające co najmniej „n” liczby
EDYTOWAĆ
Znalazłem to zapytanie (i trochę je zmieniłem)
WITH q AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY id_set, status ORDER BY number) AS rnd,
ROW_NUMBER() OVER (PARTITION BY id_set ORDER BY number) AS rn
FROM numbers
)
SELECT id_set,
MIN(number) AS first_number,
MAX(number) AS last_number,
status,
COUNT(number) AS numbers_count
FROM q
GROUP BY id_set,
rnd - rn,
status
ORDER BY
first_number
który tworzy grupy DARMOWYCH / PRZYPISANYCH liczb, ale chciałbym mieć wszystkie liczby tylko z pierwszej grupy, która spełnia warunek
id_set
czy tylko jeden? Zaktualizuj swoje pytanie, czy to miało być jego częścią od samego początku. (Aby inni mogli zobaczyć pełne wymagania i zaoferować swoje sugestie lub zaktualizować swoje odpowiedzi.)Prosty i szybki wariant:
Wymaga ciągłej sekwencji liczb w
number
(jak podano w pytaniu).Działa dla dowolnej liczby możliwych wartości
status
poza'FREE'
, nawet zNULL
.Główną cechą jest to, aby odjąć
row_number()
odnumber
po wyeliminowaniu niekwalifikujących wiersze. Kolejne liczby kończą się w tym samymgrp
- igrp
gwarantuje się, że będą w porządku rosnącym .Następnie możesz
GROUP BY grp
i policzyć członków. Ponieważ wydaje się, że chcesz pierwszego wystąpienia,ORDER BY grp LIMIT 1
a otrzymasz pozycję początkową i długość sekwencji (może być> = n ).Zestaw wierszy
Aby uzyskać rzeczywisty zestaw liczb, nie przeglądaj tabeli innym razem. Znacznie taniej z
generate_series()
:Jeśli faktycznie chcesz ciąg z zerami wiodącymi, taki jak w przykładowych wartościach, użyj
to_char()
zFM
modyfikatorem (tryb wypełnienia):SQL Fiddle z rozszerzonym przypadkiem testowym i obydwoma zapytaniami.
Ściśle związana odpowiedź:
źródło
Jest to dość ogólny sposób na zrobienie tego.
Pamiętaj, że to zależy od tego, czy
number
kolumna jest po kolei. Jeśli nie jest to funkcja Windows i / lub rozwiązanie typu CTE, prawdopodobnie będzie potrzebne:źródło
M.number-consec+1
(np. Dla 10 musiałoby to być10-3+1=8
).number
pola. Dobry sprawdzian z matematyki, poprawię to.EXISTS
można uprościć. Ponieważ musimy tylko upewnić się, że istnieje n wcześniejszych wierszy, możemy upuścićAND status = 'FREE'
. I chciałbym zmienić stan w 2EXISTS
dostatus <> 'FREE'
utwardzenia go przed dodanych opcji w przyszłości.Zwróci tylko pierwszą z 3 liczb. Nie wymaga, aby wartości
number
były następujące po sobie. Testowane w SQL-Fiddle :I to pokaże wszystkie liczby (gdzie są 3 lub więcej kolejnych
'FREE'
pozycji):źródło
W tym przypadku 5 kolejnych liczb - dlatego różnica musi wynosić 4 lub innymi słowy
count(r3.number) = n
ir2.number = r1.number + n - 1
.Z połączeniami:
źródło
JOIN
składnią?źródło
{ }
przycisk na edytorze. Cieszyć się!