То, что вы ищете, называется " pivot " (см. Также " Pivoting Operations " в Руководстве по хранилищу данных Oracle Database):
SELECT *
FROM tbl
PIVOT(SUM(value) FOR Key IN (40, 41, 42))
Был добавлен в Oracle в 11g. Обратите внимание, что вам нужно указать столбцы результата (значения из неотключенного столбца, которые становятся именами поворотного столбца) в предложении сводки. Любые столбцы, не указанные в сводке, неявно группируются. Если в исходной таблице есть столбцы, по которым вы не хотите группировать данные, выберите их из представления или подзапроса, а не из таблицы.
Вы можете немного пообщаться с wizardry и заставить Oracle создать для вас оператор, так что вам не нужно будет выяснять, какие значения столбцов нужно развернуть. В 11g, когда вы знаете, что значения столбцов являются числовыми:
SELECT
'SELECT * FROM tbl PIVOT(SUM(value) FOR Key IN ('
|| LISTAGG(Key, ',') WITHIN GROUP (ORDER BY Key)
|| ');'
FROM tbl;
Если значения столбца могут быть не числовыми:
SELECT
'SELECT * FROM tbl PIVOT(SUM(value) FOR Key IN (\''
|| LISTAGG(Key, '\',\'') WITHIN GROUP (ORDER BY Key)
|| '\'));'
FROM tbl;
LISTAGG
вероятно, повторяет дубликаты (кто-нибудь проверит это?), В этом случае вам понадобится:
SELECT
'SELECT * FROM tbl PIVOT(SUM(value) FOR Key IN (\''
|| LISTAGG(Key, '\',\'') WITHIN GROUP (ORDER BY Key)
|| '\'));'
FROM (SELECT DISTINCT Key FROM tbl);
Вы можете пойти дальше, определив функцию, которая принимает имя таблицы, статистическое выражение и имя столбца сводной таблицы, которая возвращает сводную инструкцию, сначала производя, а затем оценивая вышеуказанную инструкцию. Затем вы можете определить процедуру, которая принимает те же аргументы и выдает поворотный результат. У меня нет доступа к Oracle 11g, чтобы проверить его, но я считаю, что это будет выглядеть примерно так:
CREATE PACKAGE dynamic_pivot AS
-- creates a PIVOT statement dynamically
FUNCTION pivot_stmt (tbl_name IN varchar2(30),
pivot_col IN varchar2(30),
aggr IN varchar2(40),
quote_values IN BOOLEAN DEFAULT TRUE)
RETURN varchar2(300);
PRAGMA RESTRICT_REFERENCES (pivot_stmt, WNDS, RNPS);
-- creates & executes a PIVOT
PROCEDURE pivot_table (tbl_name IN varchar2(30),
pivot_col IN varchar2(30),
aggr IN varchar2(40),
quote_values IN BOOLEAN DEFAULT TRUE);
END dynamic_pivot;
CREATE PACKAGE BODY dynamic_pivot AS
FUNCTION pivot_stmt (
tbl_name IN varchar2(30),
pivot_col IN varchar2(30),
aggr_expr IN varchar2(40),
quote_values IN BOOLEAN DEFAULT TRUE
) RETURN varchar2(300)
IS
stmt VARCHAR2(400);
quote VARCHAR2(2) DEFAULT '';
BEGIN
IF quote_values THEN
quote := '\\\'';
END IF;
-- "\||" shows that you are still in the dynamic statement string
-- The input fields aren't sanitized, so this is vulnerable to injection
EXECUTE IMMEDIATE 'SELECT \'SELECT * FROM ' || tbl_name
|| ' PIVOT(' || aggr_expr || ' FOR ' || pivot_col
|| ' IN (' || quote || '\' \|| LISTAGG(' || pivot_col
|| ', \'' || quote || ',' || quote
|| '\') WITHIN GROUP (ORDER BY ' || pivot_col || ') \|| \'' || quote
|| '));\' FROM (SELECT DISTINCT ' || pivot_col || ' FROM ' || tbl_name || ');'
INTO stmt;
RETURN stmt;
END pivot_stmt;
PROCEDURE pivot_table (tbl_name IN varchar2(30), pivot_col IN varchar2(30), aggr_expr IN varchar2(40), quote_values IN BOOLEAN DEFAULT TRUE) IS
BEGIN
EXECUTE IMMEDIATE pivot_stmt(tbl_name, pivot_col, aggr_expr, quote_values);
END pivot_table;
END dynamic_pivot;
Примечание. Длина параметров tbl_name
, pivot_col
и aggr_expr
определяется максимальной длиной таблицы и имени столбца . Также обратите внимание, что функция уязвима для внедрения SQL.
В версии до 11g можно применять методы генерации сводных операторов MySQL (которые генерируют тип запросов, отправленных другими, на основе явного определения отдельного столбца для каждого значения сводки).