Ответ 1
Установите дополнительный модуль 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
заполняется для первого столбца. Иногда это поведение желательно, но не для этого варианта использования. - Простая форма также ограничена ровно тремя столбцами в предоставленном входном запросе: row_name, category, value. Для дополнительных столбцов нет места, как в альтернативе с двумя параметрами ниже.
Безопасная форма
crosstab(text, text)
с двумя входными параметрами:
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'
Это в руководстве.
Поскольку вы все равно должны указывать все столбцы в списке определения столбцов (за исключением заранее определенных вариантов
crosstab N()
-crosstab N()
), обычно более эффективно предоставлять короткий список в выражении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 <> скрипка здесь
Расширенные примеры
-
Pivot на нескольких столбцах с помощью 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):
Ранее принятый ответ устарел.
-
Вариант функции
crosstab(text, integer)
устарел. Второйinteger
параметр игнорируется. Я цитирую текущее руководство:crosstab(text sql, int N)
...Устаревшая версия
crosstab(text)
. ПараметрN
теперь игнорируется, поскольку количество столбцов значений всегда определяется вызывающим запросом -
Неправильное кастинг и переименование.
-
Он не работает, если строка не имеет всех атрибутов. См. Безопасный вариант с двумя входными параметрами выше, чтобы правильно обрабатывать отсутствующие атрибуты.
-
ORDER BY
требуется в однопараметрической формеcrosstab()
. Руководство:На практике SQL-запрос должен всегда указывать
ORDER BY 1,2
чтобы убедиться, что строки ввода правильно упорядочены