[轉]decode函式和行列互換
http://tech.it168.com/a2010/0412/872/000000872348.shtml
Decode函式的語法結構如下:
decode (expression, search_1, result_1)
decode (expression, search_1, result_1, search_2, result_2)
decode (expression, search_1, result_1, search_2, result_2, ....,
search_n, result_n)
decode (expression, search_1, result_1, default)
decode (expression, search_1, result_1, search_2, result_2, default)
decode (expression, search_1, result_1, search_2, result_2, ....,
search_n, result_n, default)
作用:和case表示式實現的功能一樣,以第1 個引數為關鍵欄位,如果等於search,則結果為對應的result,最後匹配不到的結果為default。如果沒有寫default,返回null。 為了格式一致,建議匹配不到不返回結果時,寫null。如果第一個返回結果為char 或null,oracle自動轉型為varchar2,如下面例子
SELECT product_id,
DECODE (warehouse_id, 1, ’Southlake’,
2, ’San Francisco’,
3, ’New Jersey’,
4, ’Seattle’,
’Non-domestic’)
"Location of inventory" FROM inventories
WHERE product_id < 1775;
Decode 函式的主要使用:
求一箇中文排序方法,謝謝!
SELECT * FROM TEMP ORDER BY 傳送狀態;
傳送狀態 東城區 西城區 崇文區 宣武區 朝陽區 豐臺區 石景山區 海淀區 合計
成功 1,473 1,113 297 103 875 1,037 7 576 5,481
傳送中 144 3 14 0 30 0 11 8 210
合計 1,619 1,116 324 103 1,125 1,224 47 584 6,142
失敗 2 0 13 0 220 187 29 0 451
想按照如下順序排序,指定按照“傳送狀態”欄位“成功”-“傳送中”,“失敗”,"合計"的順序,即:
傳送狀態 東城區 西城區 崇文區 宣武區 朝陽區 豐臺區 石景山區 海淀區 合計
成功 1,473 1,113 297 103 875 1,037 7 576 5,481
傳送中 144 3 14 0 30 0 11 8 210
失敗 2 0 13 0 220 187 29 0 451
合計 1,619 1,116 324 103 1,125 1,224 47 584 6,142
SELECT * FROM TEMP ORDER BY DECODE(傳送狀態,'成功',1,'傳送中',2,....)
來源於select name,id from tmp order by 2;按列位置排序,使用decode則可以動態指定
主要使用在查詢結果的行列轉換上,如:
1、 固定列數的行列轉換
如
name subject grade
---------------------------
student1 語文 80
student1 數學 70
student1 英語 60
student2 語文 90
student2 數學 80
student2 英語 100
……
轉換為
語文 數學 英語
student1 80 70 60
student2 90 80 100
按照name分組得到的結果,所以decode外面要套個sum,不然group by出現語義錯誤,結果為
select name,sum(decode(subject,'語文', grade,null)) "語文",
sum(decode(subject,'數學', grade,null)) "數學",
sum(decode(subject,'英語', grade,null)) "英語"
from student
group by name
2、 不定列行列轉換
如
c1 c2
--------------
1 我
1 是
1 誰
2 知
2 道
3 不
……
轉換為
1 我是誰
2 知道
3 不
這一型別的轉換必須藉助於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;
/
SQL> select distinct c1 ,get_c2(c1) cc2 from table;即可
或者不用pl/sql,利用分析函式和 CONNECT_BY 實現:
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、列數不固定(交叉錶行列轉置)
這種是比較麻煩的一種,需要藉助pl/sql:
原始資料:
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
轉置後:
CALLDATE CallCount1 CallCount2 CallCount3
------------ ---------- ---------- ----------
2005-08-09 0 0 33
2005-08-08 40 77 9
2005-08-07 6 0 21
試驗如下:
1). 建立測試表和資料
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準備輸出結果集
CREATE OR REPLACE PACKAGE pkg_getrecord
IS
TYPE myrctype IS REF CURSOR;
END pkg_getrecord;
/
3). 建立動態sql交叉表函式,輸出結果集
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下執行:
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
4、 不分組只簡單行列互換,並且每組之間用虛線分割,可以使用procedure,程式碼如下:
create or replace
procedure print_table(p_query in varchar2)
authid current_user as
l_thecursor integer default dbms_sql.open_cursor;
l_columnvalue varchar2(4000);
l_status integer;
l_desctbl dbms_sql.desc_tab;
l_colcnt number;
begin
dbms_sql.parse(l_thecursor,p_query,dbms_sql.native);
dbms_sql.describe_columns(l_thecursor,l_colcnt,l_desctbl);
for i in 1..l_colcnt loop
dbms_sql.define_column(l_thecursor,i,l_columnvalue,4000);
end loop;
l_status := dbms_sql.execute(l_thecursor);
while(dbms_sql.fetch_rows(l_thecursor)>0) loop
for i in 1..l_colcnt loop
dbms_sql.column_value(l_thecursor,i,l_columnvalue);
dbms_output.put_line(rpad(l_desctbl(i).col_name,30)||l_c
olumnvalue);
end loop;
dbms_output.put_line('----------------------------------------------
-------');
end loop;
exception
when others then
dbms_sql.close_cursor(l_thecursor);
raise;
null;
end;
/
Decode函式的語法結構如下:
decode (expression, search_1, result_1)
decode (expression, search_1, result_1, search_2, result_2)
decode (expression, search_1, result_1, search_2, result_2, ....,
search_n, result_n)
decode (expression, search_1, result_1, default)
decode (expression, search_1, result_1, search_2, result_2, default)
decode (expression, search_1, result_1, search_2, result_2, ....,
search_n, result_n, default)
作用:和case表示式實現的功能一樣,以第1 個引數為關鍵欄位,如果等於search,則結果為對應的result,最後匹配不到的結果為default。如果沒有寫default,返回null。 為了格式一致,建議匹配不到不返回結果時,寫null。如果第一個返回結果為char 或null,oracle自動轉型為varchar2,如下面例子
SELECT product_id,
DECODE (warehouse_id, 1, ’Southlake’,
2, ’San Francisco’,
3, ’New Jersey’,
4, ’Seattle’,
’Non-domestic’)
"Location of inventory" FROM inventories
WHERE product_id < 1775;
Decode 函式的主要使用:
求一箇中文排序方法,謝謝!
SELECT * FROM TEMP ORDER BY 傳送狀態;
傳送狀態 東城區 西城區 崇文區 宣武區 朝陽區 豐臺區 石景山區 海淀區 合計
成功 1,473 1,113 297 103 875 1,037 7 576 5,481
傳送中 144 3 14 0 30 0 11 8 210
合計 1,619 1,116 324 103 1,125 1,224 47 584 6,142
失敗 2 0 13 0 220 187 29 0 451
想按照如下順序排序,指定按照“傳送狀態”欄位“成功”-“傳送中”,“失敗”,"合計"的順序,即:
傳送狀態 東城區 西城區 崇文區 宣武區 朝陽區 豐臺區 石景山區 海淀區 合計
成功 1,473 1,113 297 103 875 1,037 7 576 5,481
傳送中 144 3 14 0 30 0 11 8 210
失敗 2 0 13 0 220 187 29 0 451
合計 1,619 1,116 324 103 1,125 1,224 47 584 6,142
SELECT * FROM TEMP ORDER BY DECODE(傳送狀態,'成功',1,'傳送中',2,....)
來源於select name,id from tmp order by 2;按列位置排序,使用decode則可以動態指定
主要使用在查詢結果的行列轉換上,如:
1、 固定列數的行列轉換
如
name subject grade
---------------------------
student1 語文 80
student1 數學 70
student1 英語 60
student2 語文 90
student2 數學 80
student2 英語 100
……
轉換為
語文 數學 英語
student1 80 70 60
student2 90 80 100
按照name分組得到的結果,所以decode外面要套個sum,不然group by出現語義錯誤,結果為
select name,sum(decode(subject,'語文', grade,null)) "語文",
sum(decode(subject,'數學', grade,null)) "數學",
sum(decode(subject,'英語', grade,null)) "英語"
from student
group by name
2、 不定列行列轉換
如
c1 c2
--------------
1 我
1 是
1 誰
2 知
2 道
3 不
……
轉換為
1 我是誰
2 知道
3 不
這一型別的轉換必須藉助於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;
/
SQL> select distinct c1 ,get_c2(c1) cc2 from table;即可
或者不用pl/sql,利用分析函式和 CONNECT_BY 實現:
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、列數不固定(交叉錶行列轉置)
這種是比較麻煩的一種,需要藉助pl/sql:
原始資料:
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
轉置後:
CALLDATE CallCount1 CallCount2 CallCount3
------------ ---------- ---------- ----------
2005-08-09 0 0 33
2005-08-08 40 77 9
2005-08-07 6 0 21
試驗如下:
1). 建立測試表和資料
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準備輸出結果集
CREATE OR REPLACE PACKAGE pkg_getrecord
IS
TYPE myrctype IS REF CURSOR;
END pkg_getrecord;
/
3). 建立動態sql交叉表函式,輸出結果集
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下執行:
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
4、 不分組只簡單行列互換,並且每組之間用虛線分割,可以使用procedure,程式碼如下:
create or replace
procedure print_table(p_query in varchar2)
authid current_user as
l_thecursor integer default dbms_sql.open_cursor;
l_columnvalue varchar2(4000);
l_status integer;
l_desctbl dbms_sql.desc_tab;
l_colcnt number;
begin
dbms_sql.parse(l_thecursor,p_query,dbms_sql.native);
dbms_sql.describe_columns(l_thecursor,l_colcnt,l_desctbl);
for i in 1..l_colcnt loop
dbms_sql.define_column(l_thecursor,i,l_columnvalue,4000);
end loop;
l_status := dbms_sql.execute(l_thecursor);
while(dbms_sql.fetch_rows(l_thecursor)>0) loop
for i in 1..l_colcnt loop
dbms_sql.column_value(l_thecursor,i,l_columnvalue);
dbms_output.put_line(rpad(l_desctbl(i).col_name,30)||l_c
olumnvalue);
end loop;
dbms_output.put_line('----------------------------------------------
-------');
end loop;
exception
when others then
dbms_sql.close_cursor(l_thecursor);
raise;
null;
end;
/
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23590362/viewspace-660113/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 用ORACLE分析函式實現行列轉換Oracle函式
- 【SQL 分析函式】wm_concat 行列轉換SQL函式
- Oracle行列互換總結Oracle
- oracle 行列互換總結Oracle
- 行列轉換
- 使用listagg函式完成行列轉換一例函式
- 在Word中實現表格的行列互換 (轉)
- oracle和mysql的行列轉換OracleMySql
- decode函式函式
- Kettle行列轉換
- 偽行列轉換!
- 行列轉換sqlSQL
- 行列轉換 交叉表 (轉)
- 轉換函式函式
- Spark實現行列轉換pivot和unpivotSpark
- 用oracle分析函式進行行列轉向Oracle函式
- Oracle-行列轉換Oracle
- MySQL行列轉換拼接MySql
- 行列轉換之大全~~~
- sql server 行列轉換SQLServer
- 報表如何實現行列互換效果?
- oracle行列轉換-多行轉換成字串Oracle字串
- 行列轉換,列行轉換統計
- Case表示式與decode()函式函式
- oracle行列轉換-行轉列Oracle
- oracle行列轉換-列轉行Oracle
- mysql行列轉換詳解MySql
- sql server行列轉換案例SQLServer
- Oracle 行列轉換 經典Oracle
- Oracle 行列轉換總結Oracle
- Oracle 行列轉換小結Oracle
- 【SQL 學習】行列轉換SQL
- 【SQL】行列轉換方法示例SQL
- Oracle行列轉換總結Oracle
- Shell練習 行列轉換
- 複雜的行列轉換
- numtoyminterval函式——數字轉換函式函式
- oracle行列轉換-字串轉換成多列Oracle字串