1

Temat: grupy przedziałów

Mam w tabeli pole nr_szt, dane są typu int. Mam przykładowe dane, które nie zawsze są jeden za drugim typu 1,2,3.....50:

1,2,3,4,9,10,11,12,20,21,22,23,24,25

Potrzebuję stworzyć zapytanie, tak aby otrzymać nr sztuk od do - w tym przypadku wynik powinien być następujący:
1-4,9-12,20-25

to jak pobrać pierwszy czy ostatni to wiem, ale z przedziałami to już nie wiem.

Ostatnio edytowany przez przesq (2012-02-14 14:33:30)

2

Odp: grupy przedziałów

Szczerze pisząc nie mam pomysłów jak to rozwiązać w prosty sposób, choć nie wykluczam, że taki istnieje i chętnie bym to zobaczył, poniżej moje toporne rozwiązanie, w skrócie prawy join na (dynamicznie) wygenerowaną serię, zrzucenie do tablicy, konwersja i obcięcie na string odzdzielony przecinkami, split oparty o wyrażenie regularne, z powrotem złożenie stringów do już podzielonych tablic i wyciągnięcie krańców przedziałów dla każdej z nich, dzięki użyciu case'a powinno dać się obsługiwać pojedyncze wartości (CTE dodałem dla czytelności, oprócz tego przyjąłem, że bazowa tabela nazywa się dane):

With dane_split As (
    Select regexp_split_to_table(regexp_replace(array_agg(dane.nr_szt)::text, '[{}]', '', 'g'), '(,NULL)+,') As split From dane Right Join
    (Select nr_szt From generate_series((Select min(nr_szt) From dane), (Select max(nr_szt) From dane)) nr_szt) s On dane.nr_szt = s.nr_szt)
Select
    Case When (array_length(dane_array, 1) > 1) Then
        dane_array[1]::text || '-' || dane_array[array_length(dane_array, 1)]::text
    Else dane_array[1]::text End
From (Select string_to_array(split, ',')::int[] As dane_array From dane_split) s;

Wynik:

 dane_array 
------------
 1-4
 9-12
 20-25
(3 rows)

Druga możliwość jaką widzę, to użycie języka proceduralnego np. PL/pgSQL, ale tam też trzeba się trochę napisać.

3

Odp: grupy przedziałów

otrzymuję błąd

ERROR:  syntax error at or near "With dane_split"
LINE 1: With dane_split As (
        ^

********** Błąd **********

ERROR: syntax error at or near "With dane_split"
Stan SQL:42601
Znak:1

czy muszę zainstalować jakąś funkcję?
wersja 8.3

4

Odp: grupy przedziałów

Select
    Case When (array_length(dane_array, 1) > 1) Then
        dane_array[1]::text || '-' || dane_array[array_length(dane_array, 1)]::text
    Else dane_array[1]::text End
From
    (Select string_to_array(split, ',')::int[] As dane_array From 
        (Select regexp_split_to_table(regexp_replace(array_agg(dane.nr_szt)::text, '[{}]', '', 'g'), '(,NULL)+,') As split From dane Right Join
        (Select nr_szt From generate_series((Select min(nr_szt) From dane), (Select max(nr_szt) From dane)) nr_szt) rs On dane.nr_szt = rs.nr_szt) ds
    ) s;

5

Odp: grupy przedziałów

Select
    Case When (array_upper(dane_array, 1) > 1) Then
        dane_array[1]::text || '-' || dane_array[array_upper(dane_array, 1)]::text
    Else dane_array[1]::text End
From
    (Select string_to_array(split, ',')::int[] As dane_array From 
        (Select regexp_split_to_table(regexp_replace(array_agg(dane.nr_szt)::text, '[{}]', '', 'g'), '(,NULL)+,') As split From dane Right Join
        (Select nr_szt From generate_series((Select min(nr_szt) From dane), (Select max(nr_szt) From dane)) nr_szt) rs On dane.nr_szt = rs.nr_szt) ds
    ) s;

Ostatnio edytowany przez przesq (2012-02-17 10:12:02)

6

Odp: grupy przedziałów

Użyj zamiast tego array_upper, jako drugi parametr także jedynka.