Установите дополнительный модуль 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);
Возвращает:
Раздел | Активный | Неактивный
--------- + -------- + ----------
A | 1 | 2
Б | 4 | 5
C | 7 | - !!
- Нет необходимости в кастинге и переименовании.
- Обратите внимание на неверный результат для
C
: значение 7
заполнено для первого столбца. Иногда такое поведение желательно, но не для этого варианта использования.
- Простая форма также ограничена ровно тремя столбцами в предоставленном входном запросе: row_name , category , value . Нет места для дополнительных столбцов, как в альтернативе с двумя параметрами ниже.
Безопасная форма
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);
Возвращает:
Раздел | Активный | Неактивный
--------- + -------- + ----------
A | 1 | 2
Б | 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)
руководства приведен пример кода .
дБ <> скрипка здесь
Расширенные примеры
\crosstabview
в PSQL
Postgres 9.6 добавил эту мета-команду к своему интерактивному терминалу psql по умолчанию . Вы можете запустить запрос, который вы будете использовать в качестве первого crosstab()
параметра, и передать его \crosstabview
(немедленно или на следующем шаге). Подобно:
db=> SELECT section, status, ct FROM tbl \crosstabview
Результат, аналогичный приведенному выше, но это функция представления исключительно на стороне клиента . Входные строки обрабатываются немного по-разному, поэтому ORDER BY
не требуется. Подробности \crosstabview
в руководстве. Внизу этой страницы есть больше примеров кода.
Соответствующий ответ на dba.SE Даниэля Верите (автор функции psql):
Ранее принят ответ устарел.
Вариант функции crosstab(text, integer)
устарел. Второй integer
параметр игнорируется. Я цитирую текущее руководство :
crosstab(text sql, int N)
...
Устаревшая версия crosstab(text)
. Параметр N
теперь игнорируется, поскольку количество столбцов значений всегда определяется вызывающим запросом.
Ненужное литье и переименование.
Сбой, если строка не имеет всех атрибутов. См. Безопасный вариант с двумя входными параметрами выше для правильной обработки отсутствующих атрибутов.
ORDER BY
требуется в однопараметрической форме crosstab()
. Руководство:
На практике SQL-запрос должен всегда указывать, ORDER BY 1,2
чтобы гарантировать, что входные строки правильно упорядочены