Повернуть таблицу в PostgreSQL можно при помощи функции CROSSTAB. Эта функция принимает в качестве текстового параметра SQL-запрос, который возвращает 3 столбца:
идентификатор строки - т.е. этот столбец содержит значения, определяющие результирующую (повернутую) строку;
категорию - уникальные значения из этого столбца образуют столбцы повернутой таблицы. Нужно отметить, что в отличие от PIVOTсами значения роли не играют; важно лишь их количество, которое определяет максимально допустимое количество столбцов;
значение категории - собственно значения категорий. Размещение значений по столбцам производится слева направо, и имена категорий роли не играют, а только их порядок, определяемый сортировкой запроса.
Поясним сказанное на примере базы данных "Окраска".
Давайте для каждого квадрата просуммируем количество краски каждого цвета:
Консоль
Выполнить
SELECT b_q_id, v_color, SUM(b_vol) qty FROM utb JOIN utv ON b_v_id = v_id
WHERE b_q_id BETWEEN12AND16
GROUPBY b_q_id, v_color
ORDERBY b_q_id, CASE v_color WHEN'R'THEN1WHEN'G'THEN2ELSE3END;
Здесь мы ограничились только квадратами с номерами в диапазоне 12-16, чтобы, с одной стороны, уменьшить вывод, а, с другой стороны, сделать вывод презентативным. Сортировка по цветам выполнена в порядке RGB. Вот результат:
b_q_id
v_color
Qty
12
R
255
12
G
255
12
B
255
13
B
123
14
R
50
14
B
111
15
R
100
15
G
100
16
G
100
16
B
150
В терминологии CROSSTAB номера баллонов являются идентификаторами строк, а цвета - категориями. Результат поворота должен быть следующим:
square
R
G
B
12
255
255
255
13
123
14
50
111
15
100
100
16
100
150
Теперь с помощью CROSSTAB попытаемся написать запрос, который бы дал требуемый результат:
SELECT * FROM
crosstab(
$$select b_q_id, v_color, SUM(b_vol) qty FROM utb JOIN utv ON b_v_id = v_id
WHERE b_q_id BETWEEN12AND16
GROUPBY b_q_id, v_color
ORDERBY b_q_id, CASE v_color WHEN'R'THEN1WHEN'G'THEN2ELSE3END; $$
Здесь мы должны перечислить список столбцов с указанием их типа. При этом столбцы категорий могут быть перечислены не все. Посмотрим на результат (вы можете проверять запросы в консоли, выбрав для исполнения PostgreSQL):
square
R
G
B
12
255
255
255
13
123
14
50
111
15
100
100
16
100
150
Этот результат не вполне совпадает с ожидаемым. Напомним, что здесь важен только порядок. Если квадрат окрашивался только одним цветом, то значение (суммарный объем краски) попадет в первую категорию (у нас она называется R), каким бы этот единственный цвет ни был. Давайте перепишем запрос таким образом, чтобы он давал значения для всех цветов причем в нужном порядке. При этом отсутствующий цвет будем заменять NULL-значением. Чтобы добиться этого, добавим для каждого квадрата по одной строке каждого цвета со значением объема краски равным NULL:
Консоль
Выполнить
SELECT b_q_id, v_color, SUM(b_vol) qty FROM(
SELECT b_q_id, v_color, b_vol FROM utb
JOIN utv ON b_v_id = v_id
UNIONALL--вот эта добавка
SELECT * FROM(SELECTDISTINCT b_q_id FROM utb) X
CROSSJOIN(SELECT'R' color, NULL::smallint vol
UNIONALLSELECT'G', NULLUNIONALLSELECT'B', NULL) Y
) X
WHERE b_q_id BETWEEN12AND16
GROUPBY b_q_id, v_color
ORDERBY b_q_id, CASE v_color WHEN'R'THEN1WHEN'G'THEN2ELSE3END;
Наверное, у вас уже возник вопрос: а нельзя ли это сделать как-нибудь проще?
Ответ положительный. Оказывается, у функции CROSSTAB есть второй необязательный параметр - запрос, возвращающий список категорий в том же порядке, в котором выводятся столбцы. Тогда первый запрос, чтобы он давал правильный результат, мы можем переписать следующим образом:
SELECT * FROM
crosstab(
$$select b_q_id, v_color, SUM(b_vol) qty FROM utb JOIN utv ON b_v_id = v_id
WHERE b_q_id BETWEEN12AND16
GROUPBY b_q_id, v_color
ORDERBY b_q_id, CASE v_color WHEN'R'THEN1WHEN'G'THEN2ELSE3END; $$,
Поскольку PostgreSQL допускает использование конструктора таблиц, запрос
SELECT'R'UNIONALLSELECT'G'UNIONALLSELECT'B';
можно заменить на более короткий:
VALUES('R'),('G'),('B');
Если вы при выполнении запроса получаете ошибку, что функции crosstab не существует, это означает, что у вас не установлен модуль tablefunc. Он устанавливается простой командой (начиная с версии 9.1)
CREATE EXTENSION IFNOTEXISTS tablefunc;
для конкретной базы данных. Для версий, предшествующих 9.1, достаточно загрузить в pgadmin следующий файл share/contrib/tablefunc.sql и выполнить его.