Инсталирайте допълнителния модул tablefunc
веднъж на база данни, която предоставя функцията crosstab()
. От Postgres 9.1 можете да използвате CREATE EXTENSION
за това:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Подобрен тестов случай
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
Прост формуляр – не е подходящ за липсващи атрибути
crosstab(text)
с1 входен параметър:
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);
Връща:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | 7 | -- !!
- Няма нужда от прехвърляне и преименуване.
- Обърнете внимание на неправилното резултат за
C
:стойността7
се попълва за първата колона. Понякога това поведение е желателно, но не и за този случай на употреба. - Опростената форма също е ограничена до точно три колони в предоставената входна заявка:име_на_ред , категория , стойност . Няма място за допълнителни колони като в алтернативата с 2 параметъра по-долу.
Безопасен формуляр
crosstab(text, text)
с2 входни параметри:
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);
Връща:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | | 7 -- !!
-
Обърнете внимание на правилния резултат за
C
. -
Вторият параметър може да бъде всяка заявка, която връща един ред на атрибут, съответстващ на реда на дефиницията на колоната в края. Често ще искате да потърсите различни атрибути от основната таблица по следния начин:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
Това е в ръководството.
Тъй като така или иначе трябва да посочите всички колони в списъка с дефиниции на колони (с изключение на предварително дефинирания crosstabN()
варианти), обикновено е по-ефективно да предоставите кратък списък в VALUES
израз, както е показано:
$$VALUES ('Active'::text), ('Inactive')$$)
Или (не е в ръководството):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
Използвах доларово котиране за улесняване на цитирането.
-
Можете дори да извеждате колони сразлични типове данни с
crosstab(text, text)
- стига текстовото представяне на колоната за стойност е валидно въвеждане за целевия тип. По този начин може да имате атрибути от различен вид и да извеждатеtext
,date
,numeric
и др. за съответните атрибути. В края на главата има пример за кодcrosstab(text, text)
в ръководството.
db<>цигулка тук
Ефект от излишните входни редове
Излишните редове за въвеждане се обработват по различен начин – дублиращи се редове за една и съща комбинация („име_на_на“, „категория“) – (section, status)
в горния пример.
1-параметър формуляр попълва налични колони за стойности отляво надясно. Излишните стойности се отхвърлят.
По-ранните редове за въвеждане печелят.
2-параметърът Формата присвоява всяка входна стойност на специалната й колона, като презаписва всяко предишно присвояване.
По-късно въведените редове печелят.
Обикновено нямате дубликати за начало. Но ако го направите, внимателно коригирайте реда на сортиране към вашите изисквания - и документирайте какво се случва.
Или получете бързи произволни резултати, ако не ви пука. Просто имайте предвид ефекта.
Разширени примери
-
Завъртане върху множество колони с помощта на Tablefunc – също така демонстрира споменатите „допълнителни колони“
-
Динамична алтернатива на завъртане с CASE и GROUP BY
\crosstabview
в psql
Postgres 9.6 добави тази мета-команда към своя интерактивен терминал по подразбиране psql. Можете да изпълните заявката, която бихте използвали като първа crosstab()
параметър и го подайте към \crosstabview
(веднага или в следващата стъпка). Като:
db=> SELECT section, status, ct FROM tbl \crosstabview
Резултатът е подобен като по-горе, но това е функция за представяне от страна на клиента единствено и само. Входните редове се третират малко по-различно, следователно ORDER BY
не се изисква. Подробности за \crosstabview
в ръководството. Има още примери за код в долната част на тази страница.
Свързан отговор на dba.SE от Daniel Vérité (авторът на функцията psql):
- Как да генерирам завъртано CROSS JOIN, където получената дефиниция на таблицата е неизвестна?