換位表我有一個表,如:通過選擇查詢
Key type value
---------------------
40 A 12.34
41 A 10.24
41 B 12.89
我想它的格式爲:
Types 40 41 42 (keys)
---------------------------------
A 12.34 10.24 XXX
B YYY 12.89 ZZZ
這怎麼可能通過SQL查詢來完成。案例陳述,解碼?
換位表我有一個表,如:通過選擇查詢
Key type value
---------------------
40 A 12.34
41 A 10.24
41 B 12.89
我想它的格式爲:
Types 40 41 42 (keys)
---------------------------------
A 12.34 10.24 XXX
B YYY 12.89 ZZZ
這怎麼可能通過SQL查詢來完成。案例陳述,解碼?
你正在尋找所謂的「pivot」(也稱「Pivoting Operations」看到Oracle數據庫數據倉庫指南):
SELECT *
FROM tbl
PIVOT(SUM(value) FOR Key IN (40, 41, 42))
它加入到Oracle 11g中。請注意,您需要在pivot子句中指定結果列(來自未轉義列的值,它們將成爲pivoted列名稱)。任何未在數據透視表中指定的列都被隱式分組。如果原始表中的列不想分組,請從視圖或子查詢中選擇,而不是從表中選擇。
您可以參與一點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);
你可以走的更遠,定義一個函數,它接受一個表名,合計表達和樞軸列名,通過第一p返回一個支點聲明然後再評估上述說法。然後,您可以定義一個採用相同參數並生成旋轉結果的過程。我沒有訪問到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注入的影響。
在pre-11g中,您可以應用MySQL pivot statement generation技術(根據顯式定義每個樞軸值的單獨列來生成他人發佈的查詢類型)。
從來沒有嘗試過,但似乎至少甲骨文11具有樞條款
樞軸確實大大簡化事情。但是,在11g之前,您需要手動執行此操作。
select
type,
sum(case when key = 40 then value end) as val_40,
sum(case when key = 41 then value end) as val_41,
sum(case when key = 42 then value end) as val_42
from my_table
group by type;
如果您無權訪問11g,則可以使用字符串聚合和分組方法來約略。您正在尋找諸如
with data as(
SELECT 40 KEY , 'A' TYPE , 12.34 VALUE FROM DUAL UNION
SELECT 41 KEY , 'A' TYPE , 10.24 VALUE FROM DUAL UNION
SELECT 41 KEY , 'B' TYPE , 12.89 VALUE FROM DUAL
)
select
TYPE ,
wm_concat(KEY) KEY ,
wm_concat(VALUE) VALUE
from data
GROUP BY TYPE;
type KEY VALUE
------ ------- -----------
A 40,41 12.34,10.24
B 41 12.89
這是什麼是根據wm_concat如下所示:http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php
我要以防萬一它有助於離開這裏,但我覺得PIVOT或MikeyByCrikey的回答會在重新查看您的樣本結果後,最符合您的需求。
它適用於Oracle 11,但對於早期版本,方法在此處提供http://www.orafaq.com/wiki/PIVOT – 2010-12-10 14:20:01