您要查找的内容称为“pivot”(另请参见 Oracle 数据库数据仓库指南中的“Pivoting Operations”):
SELECT *
FROM tbl
PIVOT(SUM(value) FOR Key IN (40, 41, 42))
它在 11g 中被添加到 Oracle。请注意,您需要在数据透视子句中指定结果列(未透视列中的值成为透视列名称)。任何未在数据透视表中指定的列都被隐式分组。如果您不想在原始表中进行分组,请从视图或子查询中进行选择,而不是从表中进行选择。
您可以参与一点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参数的长度来自maximum table and column name length。另请注意,该函数易受 SQL 注入攻击。
在 11g 之前的版本中,您可以应用 MySQL pivot statement generation 技术(根据为每个数据透视值显式定义单独的列,生成其他人发布的查询类型)。