select * from table pivot( sum([value]) for [ITEM] in ([A_MAX_CURRENTL],[A_MAX_CURRENTU],[A_MOTOR_PI_COUNTL],....))as s
在溫宿等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站建設(shè)、成都網(wǎng)站制作 網(wǎng)站設(shè)計制作按需定制開發(fā),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),全網(wǎng)整合營銷推廣,成都外貿(mào)網(wǎng)站制作,溫宿網(wǎng)站建設(shè)費(fèi)用合理。
舉例說明:
1、固定列數(shù)的行列轉(zhuǎn)換
如
student subject grade
--------- ---------- --------
student1 語文 80
student1 數(shù)學(xué) 70
student1 英語 60
student2 語文 90
student2 數(shù)學(xué) 80
student2 英語 100
……
轉(zhuǎn)換為
語文 數(shù)學(xué) 英語
student1 80 70 60
student2 90 80 100
……
語句如下:select student,
sum(decode(subject,'語文', grade,null)) "語文",
sum(decode(subject,'數(shù)學(xué)', grade,null)) "數(shù)學(xué)",
sum(decode(subject,'英語', grade,null)) "英語"
from table
group by student;
2、不定列行列轉(zhuǎn)換
如
c1 c2
--- -----------
1 我
1 是
1 誰
2 知
2 道
3 不
……
轉(zhuǎn)換為
1 我是誰
2 知道
3 不
這一類型的轉(zhuǎn)換可以借助于PL/SQL來完成,這里給一個例子
CREATE OR REPLACE FUNCTION get_c2(tmp_c1 NUMBER)
RETURN VARCHAR2
IS
Col_c2 VARCHAR2(4000);
BEGIN
FOR cur IN (SELECT c2 FROM t WHERE c1=tmp_c1) LOOP
Col_c2 := Col_c2||cur.c2;
END LOOP;
Col_c2 := rtrim(Col_c2,1);
RETURN Col_c2;
END;
select distinct c1 ,get_c2(c1) cc2 from table;
或者不用pl/sql,利用分析函數(shù)和 CONNECT_BY 實(shí)現(xiàn):
SELECT c1, SUBSTR (MAX (SYS_CONNECT_BY_PATH (c2, ';')), 2) NAME
FROM (SELECT c1, c2, rn, LEAD (rn) OVER (PARTITION BY c1 ORDER BY rn) rn1
FROM (SELECT c1, c2, ROW_NUMBER () OVER (ORDER BY c2) rn
FROM t))
START WITH rn1 IS NULL
CONNECT BY rn1 = PRIOR rn
GROUP BY c1;
3、列數(shù)不固定(交叉表行列轉(zhuǎn)置)
這種是比較麻煩的一種,需要借助pl/sql:
原始數(shù)據(jù):
CLASS1 CALLDATE CALLCOUNT
1 2005-08-08 40
1 2005-08-07 6
2 2005-08-08 77
3 2005-08-09 33
3 2005-08-08 9
3 2005-08-07 21
轉(zhuǎn)置后:
CALLDATE CallCount1 CallCount2 CallCount3
------------ ---------- ---------- ----------
2005-08-09 0 0 33
2005-08-08 40 77 9
2005-08-07 6 0 21
試驗如下:
1). 建立測試表和數(shù)據(jù)
CREATE TABLE t(
class1 VARCHAR2(2 BYTE),
calldate DATE,
callcount INTEGER
);
INSERT INTO t(class1, calldate, callcount)
VALUES ('1', TO_DATE ('08/08/2005', 'MM/DD/YYYY'), 40);
INSERT INTO t(class1, calldate, callcount)
VALUES ('1', TO_DATE ('08/07/2005', 'MM/DD/YYYY'), 6);
INSERT INTO t(class1, calldate, callcount)
VALUES ('2', TO_DATE ('08/08/2005', 'MM/DD/YYYY'), 77);
INSERT INTO t(class1, calldate, callcount)
VALUES ('3', TO_DATE ('08/09/2005', 'MM/DD/YYYY'), 33);
INSERT INTO t(class1, calldate, callcount)
VALUES ('3', TO_DATE ('08/08/2005', 'MM/DD/YYYY'), 9);
INSERT INTO t(class1, calldate, callcount)
VALUES ('3', TO_DATE ('08/07/2005', 'MM/DD/YYYY'), 21);
COMMIT ;
2). 建立ref cursor準(zhǔn)備輸出結(jié)果集
CREATE OR REPLACE PACKAGE pkg_getrecord
IS
TYPE myrctype IS REF CURSOR;
END pkg_getrecord;
/
3). 建立動態(tài)sql交叉表函數(shù),輸出結(jié)果集
CREATE OR REPLACE FUNCTION fn_rs
RETURN pkg_getrecord.myrctype
IS
s VARCHAR2 (4000);
CURSOR c1 IS
SELECT ',sum(case when Class1='
|| class1
|| ' then CallCount else 0 end)'
|| ' "CallCount'
|| class1
|| '"' c2
FROM t
GROUP BY class1;
r1 c1%ROWTYPE;
list_cursor pkg_getrecord.myrctype;
BEGIN
s := 'select CallDate ';
OPEN c1;
LOOP
FETCH c1 INTO r1;
EXIT WHEN c1%NOTFOUND;
s := s || r1.c2;
END LOOP;
CLOSE c1;
s := s || ' from T group by CallDate order by CallDate desc ';
OPEN list_cursor FOR s;
RETURN list_cursor;
END fn_rs;
/
4). 測試在sql plus下執(zhí)行:
var results refcursor;
exec :results := fn_rs;
print results;
CALLDATE CallCount1 CallCount2 CallCount3
--------------- ---------- ---------- ----------
2005-08-09 0 0 33
2005-08-08 40 77 9
2005-08-07 6 0 21
select 廠家,
sum(case when 列別 = 棉衣 then 1 else 0 end) 棉衣,
sum(case when 列別 = 風(fēng)衣 then 1 else 0 end) 風(fēng)衣 ,
sum(case when 列別 = 背心 then 1 else 0 end) 背心
from 表
group by 廠家
用C#實(shí)現(xiàn)矩陣的轉(zhuǎn)置。
假設(shè) 原矩陣式 a是int [m,n],新定義一個二位數(shù)組b是int [n,m]
然后對每個b的元素b[x,y]賦值 a[y,x]
如果字段存的就是這個,那么這個應(yīng)該是字符串吧,那么就分幾步操作。
(1)定位,定位{和:的位置,從現(xiàn)在來看有兩種可能,第一種
這是兩個字段,分別是{12345:67:8}和{ABC:0:9},那就簡單了{(lán)肯定是1,所以這個也就不需要定位了,只需要定位第一個冒號的位置。
定位的函數(shù)應(yīng)該是instr
第二種:{12345:67:8}{ABC:0:9}是一個字段的內(nèi)容,那就麻煩一些,不過也能做,希望不是這樣的,因為這個就要麻煩很多了。正則倒是能做,不過正則都要測試,我可沒有相應(yīng)的環(huán)境做測試。這里也就不寫了,如果是這種,那么自己翻一翻正則函數(shù)的用法,應(yīng)該能寫出來。
(2)截取,如果是第一種,那么定位了第一個冒號位置以后,用這個位置-2,也就是
instr(字段,':',1)-2這就是截取的長度,
從第二位開始截取,截取這個長度就可以substr(字段,2,instr(字段,':',1)-2)
這樣的話,{12345:67:8}換算到內(nèi)部就是substr({12345:67:8},2,5(7-2)),【7-2說明5的來源,第一個冒號在第7位】,截取出來就是12345
還是那句話,如果是第二種可能,那么就要找每一個{的位置,然后找在{后面距離最近的冒號的位置,然后再一個個的截取操作,正則應(yīng)該可以操作,不過我還是那句話,需要測試,意思和這個截取函數(shù)差不多,自己好好理解一下應(yīng)該就能操作了。
一般行列轉(zhuǎn)置,有兩種做法
一種是case,但是由于case需要提前知道列數(shù),所以在很多情況下不能滿足
所以出現(xiàn)了動態(tài)語句case,通過動態(tài)SQL語句的組裝,實(shí)現(xiàn)了動態(tài)的列的拼裝。但是語句復(fù)雜度很高
所以另一種方式就是靠程序轉(zhuǎn)置,使用一些Hash(JAVA)或Dictionary(C#)等一些對象,可以在程序中輕松地做出轉(zhuǎn)置,但是也有缺點(diǎn),缺點(diǎn)就是開銷大,原本只處理一次的數(shù)據(jù)(只在數(shù)據(jù)庫處理),現(xiàn)在需要處理兩次(數(shù)據(jù)庫一次,程序一次)