Zainstaluj dodatkowy moduł tablefunc
raz na bazę danych, która udostępnia funkcję crosstab()
. Od Postgres 9.1 możesz używać CREATE EXTENSION
za to:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Ulepszony przypadek testowy
CREATE TABLE tbl (
section text
, status text
, ct integer -- "count" is a reserved word in standard SQL
);
INSERT INTO tbl VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7); -- ('C', 'Active') is missing
Prosty formularz – nie pasuje do brakujących atrybutów
crosstab(text)
z 1 parametr wejściowy:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- needs to be "ORDER BY 1,2" here
) AS ct ("Section" text, "Active" int, "Inactive" int);
Zwroty:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | 7 | -- !!
- Nie ma potrzeby przesyłania i zmiany nazwy.
- Zwróć uwagę na niepoprawne wynik dla
C
:wartość7
jest wypełniana w pierwszej kolumnie. Czasami takie zachowanie jest pożądane, ale nie w tym przypadku użycia. - Prosty formularz jest również ograniczony do dokładnie trzy kolumny w podanym zapytaniu wejściowym:nazwa_wiersza , kategoria , wartość . Nie ma miejsca na dodatkowe kolumny jak w 2-parametrowej alternatywie poniżej.
Bezpieczna forma
crosstab(text, text)
z 2 parametry wejściowe:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- could also just be "ORDER BY 1" here
, $$VALUES ('Active'::text), ('Inactive')$$
) AS ct ("Section" text, "Active" int, "Inactive" int);
Zwroty:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | | 7 -- !!
-
Zanotuj poprawny wynik dla
C
. -
drugi parametr może być dowolnym zapytaniem zwracającym jeden wiersz na atrybut pasujący do kolejności definicji kolumny na końcu. Często będziesz chciał zapytać o różne atrybuty z tabeli bazowej w następujący sposób:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
To jest w instrukcji.
Ponieważ i tak musisz przeliterować wszystkie kolumny na liście definicji kolumn (z wyjątkiem predefiniowanych crosstabN()
wariantów), zazwyczaj bardziej wydajne jest dostarczenie krótkiej listy w VALUES
wyrażenie jak zademonstrowano:
$$VALUES ('Active'::text), ('Inactive')$$)
Lub (nie w instrukcji):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
Użyłem cytowania dolara aby ułatwić cytowanie.
-
Możesz nawet wyprowadzać kolumny z różnymi typy danych z
crosstab(text, text)
- o ile tekstowa reprezentacja kolumny wartości jest poprawnym wejściem dla typu docelowego. W ten sposób możesz mieć atrybuty różnego rodzaju i wyprowadzaćtext
,date
,numeric
itp. dla odpowiednich atrybutów. Na końcu rozdziału znajduje się przykładowy kodcrosstab(text, text)
w instrukcji.
db<>graj tutaj
Wpływ nadmiaru wierszy wejściowych
Nadmiarowe wiersze wejściowe są obsługiwane inaczej — zduplikowane wiersze dla tej samej kombinacji („nazwa_wiersza”, „kategoria”) — (section, status)
w powyższym przykładzie.
1-parametr formularz wypełnia dostępne kolumny wartości od lewej do prawej. Nadmiarowe wartości są odrzucane.
Wcześniejsze wiersze wejściowe wygrywają.
Dwuparametrowy formularz przypisuje każdą wartość wejściową do jej dedykowanej kolumny, zastępując poprzednie przypisanie.
Później wprowadzane wiersze wygrywają.
Zazwyczaj na początku nie masz duplikatów. Ale jeśli to zrobisz, ostrożnie dostosuj kolejność sortowania do swoich wymagań – i udokumentuj, co się dzieje.
Lub uzyskaj szybko dowolne wyniki, jeśli Ci to nie zależy. Po prostu bądź świadomy efektu.
Zaawansowane przykłady
-
Obróć wiele kolumn za pomocą funkcji Tablefunc – demonstruje również wspomniane „dodatkowe kolumny”
-
Dynamiczna alternatywa dla pivota z CASE i GROUP BY
\crosstabview
w psql
Postgres 9,6 dodał tę meta-polecenie do domyślnego interaktywnego terminala psql. Możesz uruchomić zapytanie, którego użyjesz jako pierwszy crosstab()
i prześlij go do \crosstabview
(natychmiast lub w kolejnym kroku). Na przykład:
db=> SELECT section, status, ct FROM tbl \crosstabview
Wynik podobny do powyższego, ale jest to funkcja reprezentacji po stronie klienta wyłącznie. Wiersze wejściowe są traktowane nieco inaczej, dlatego ORDER BY
nie jest wymagany. Szczegóły dotyczące \crosstabview
w instrukcji. Na dole tej strony znajduje się więcej przykładów kodu.
Powiązana odpowiedź na dba.SE autorstwa Daniela Vérité (autora funkcji psql):
- Jak wygenerować przestawne CROSS JOIN, gdy wynikowa definicja tabeli jest nieznana?