create table Table_A
(
姓名 varchar(20),
課程 varchar(20),
成績 int
)
insert into Table_A(姓名,課程,成績) values('張三','語文',60)
insert into Table_A(姓名,課程,成績) values('張三','數學',70)
insert into Table_A(姓名,課程,成績) values('張三','英語',80)
insert into Table_A(姓名,課程,成績) values('李四','語文',90)
insert into Table_A(姓名,課程,成績) values('李四','數學',100)
create table Table_B
(
姓名 varchar(20),
語文 int,
數學 int,
英語 int
)
insert into Table_B(姓名,語文,數學,英語) values('張三',60,70,80)
insert into Table_B(姓名,語文,數學,英語) values('李四',90,100,0)
select 姓名,
sum (case 課程 when '語文' then 成績 else 0 end) as 語文,
sum (case 課程 when '數學' then 成績 else 0 end) as 數學,
sum (case 課程 when '英語' then 成績 else 0 end) as 英語
from Table_A
group by 姓名
select * from Table_A pivot (max(成績)for 課程 in(語文,數學,英語)) 臨時表
select 姓名,'語文' as 課程,語文 as 成績 from Table_B union all
select 姓名,'數學' as 課程,數學 as 成績 from Table_B union all
select 姓名,'英語' as 課程,英語 as 成績 from Table_B
order by 姓名,課程 desc
select 姓名,課程,成績 from Table_B
unpivot
(成績 for 課程 in ([語文],[數學],英語)) 臨時表
方法二:
--用case when 實現
SELECT T.NAME,
SUM(CASE T.Course WHEN '語文' THEN T.Score ELSE 0 END) 語文,
SUM(CASE T.Course WHEN '數學' THEN T.Score ELSE 0 END) 數學,
SUM(CASE T.Course WHEN '英語' THEN T.Score ELSE 0 END) 英語
FROM T_T_STUDENT T
GROUP BY T.NAME
輸出結果以下:
姓名 語文 數學 英語
1 劉備 90 94 92
2 關羽 97 53 95
3 張飛 80 87 68
區別若是條件是單一值時,用decode比較簡便,若是判斷條件比較複雜是用case when實現
--------------------
普通行列轉換
假設有張學生成績表(tb)以下:
Name Subject Result
張三 語文 74
張三 數學 83
張三 物理 93
李四 語文 74
李四 數學 84
李四 物理 94
*/
-------------------------------------------------------------------------
/*
想變成
姓名 語文 數學 物理
---------- ----------- ----------- -----------
李四 74 84 94
張三 74 83 93
*/
create table tb
(
Name varchar(10) ,
Subject varchar(10) ,
Result int
)
insert into tb(Name , Subject , Result) values('張三' , '語文' , 74)
insert into tb(Name , Subject , Result) values('張三' , '數學' , 83)
insert into tb(Name , Subject , Result) values('張三' , '物理' , 93)
insert into tb(Name , Subject , Result) values('李四' , '語文' , 74)
insert into tb(Name , Subject , Result) values('李四' , '數學' , 84)
insert into tb(Name , Subject , Result) values('李四' , '物理' , 94)
go
--靜態SQL,指subject只有語文、數學、物理這三門課程。
select name 姓名,
max(case subject when '語文' then result else 0 end) 語文,
max(case subject when '數學' then result else 0 end) 數學,
max(case subject when '物理' then result else 0 end) 物理
from tb
group by name
/*
姓名 語文 數學 物理
---------- ----------- ----------- -----------
李四 74 84 94
張三 74 83 93
*/
--動態SQL,指subject不止語文、數學、物理這三門課程。
declare @sql varchar(8000)
set @sql = 'select Name as ' + '姓名'
select @sql = @sql + ' , max(case Subject when ''' + Subject + ''' then Result else 0 end) [' + Subject + ']'
from (select distinct Subject from tb) as a
set @sql = @sql + ' from tb group by name'
exec(@sql)
/*
姓名 數學 物理 語文
---------- ----------- ----------- -----------
李四 84 94 74
張三 83 93 74
*/
-------------------------------------------------------------------
/*加個平均分,總分
姓名 語文 數學 物理 平均分 總分
---------- ----------- ----------- ----------- -------------------- -----------
李四 74 84 94 84.00 252
張三 74 83 93 83.33 250
*/
--靜態SQL,指subject只有語文、數學、物理這三門課程。
select name 姓名,
max(case subject when '語文' then result else 0 end) 語文,
max(case subject when '數學' then result else 0 end) 數學,
max(case subject when '物理' then result else 0 end) 物理,
cast(avg(result*1.0) as decimal(18,2)) 平均分,
sum(result) 總分
from tb
group by name
/*
姓名 語文 數學 物理 平均分 總分
---------- ----------- ----------- ----------- -------------------- -----------
李四 74 84 94 84.00 252
張三 74 83 93 83.33 250
*/
--動態SQL,指subject不止語文、數學、物理這三門課程。
declare @sql1 varchar(8000)
set @sql1 = 'select Name as ' + '姓名'
select @sql1 = @sql1 + ' , max(case Subject when ''' + Subject + ''' then Result else 0 end) [' + Subject + ']'
from (select distinct Subject from tb) as a
set @sql1 = @sql1 + ' , cast(avg(result*1.0) as decimal(18,2)) 平均分,sum(result) 總分 from tb group by name'
exec(@sql1)
/*
姓名 數學 物理 語文 平均分 總分
---------- ----------- ----------- ----------- -------------------- -----------
李四 84 94 74 84.00 252
張三 83 93 74 83.33 250
*/
drop table tb
---------------------------------------------------------
---------------------------------------------------------
/*
若是上述兩表互相換一下:即
姓名 語文 數學 物理
張三 74 83 93
李四 74 84 94
想變成
Name Subject Result
---------- ------- -----------
李四 語文 74
李四 數學 84
李四 物理 94
張三 語文 74
張三 數學 83
張三 物理 93
*/
create table tb1
(
姓名 varchar(10) ,
語文 int ,
數學 int ,
物理 int
)
insert into tb1(姓名 , 語文 , 數學 , 物理) values('張三',74,83,93)
insert into tb1(姓名 , 語文 , 數學 , 物理) values('李四',74,84,94)
select * from
(
select 姓名 as Name , Subject = '語文' , Result = 語文 from tb1
union all
select 姓名 as Name , Subject = '數學' , Result = 數學 from tb1
union all
select 姓名 as Name , Subject = '物理' , Result = 物理 from tb1
) t
order by name , case Subject when '語文' then 1 when '數學' then 2 when '物理' then 3 when '總分' then 4 end
--------------------------------------------------------------------
/*加個平均分,總分
Name Subject Result
---------- ------- --------------------
李四 語文 74.00
李四 數學 84.00
李四 物理 94.00
李四 平均分 84.00
李四 總分 252.00
張三 語文 74.00
張三 數學 83.00
張三 物理 93.00
張三 平均分 83.33
張三 總分 250.00
*/
select * from
(
select 姓名 as Name , Subject = '語文' , Result = 語文 from tb1
union all
select 姓名 as Name , Subject = '數學' , Result = 數學 from tb1
union all
select 姓名 as Name , Subject = '物理' , Result = 物理 from tb1
union all
select 姓名 as Name , Subject = '平均分' , Result = cast((語文 + 數學 + 物理)*1.0/3 as decimal(18,2)) from tb1
union all
select 姓名 as Name , Subject = '總分' , Result = 語文 + 數學 + 物理 from tb1
) t
order by name , case Subject when '語文' then 1 when '數學' then 2 when '物理' then 3 when '平均分' then 4 when'總分' then 5 end
drop table tb1
--------------
動態列轉行
----------------新建測試表
CREATE TABLE tmp_user_2(USER_ID NUMBER,MODE_NAME VARCHAR2(100),TYPE_ID NUmBER);
----------------第一部分測試數據
INSERT INTO tmp_user_2 VALUES(1001, 'M1',1);
INSERT INTO tmp_user_2 VALUES(1001, 'M2',2);
INSERT INTO tmp_user_2 VALUES(1002, 'M1',3);
INSERT INTO tmp_user_2 VALUES(1002, 'M2',4);
INSERT INTO tmp_user_2 VALUES(1002, 'M3',5);
INSERT INTO tmp_user_2 VALUES(1003, 'M1',6);
COMMIT;
----------------行轉列存儲過程
CREATE OR REPLACE PROCEDURE P_tmp_user_2 IS
V_SQL VARCHAR2(2000);
CURSOR CURSOR_1 IS
SELECT DISTINCT T.MODE_NAME FROM tmp_user_2 T ORDER BY MODE_NAME;
BEGIN
V_SQL := 'SELECT USER_ID';
FOR V_XCLCK IN CURSOR_1 LOOP
V_SQL := V_SQL || ',' || 'SUM(DECODE(MODE_NAME,''' || V_XCLCK.MODE_NAME ||
''',TYPE_ID,0)) AS ' || V_XCLCK.MODE_NAME;
END LOOP;
V_SQL := V_SQL || ' FROM tmp_user_2 GROUP BY USER_ID';
--DBMS_OUTPUT.PUT_LINE(V_SQL);
V_SQL := 'CREATE OR REPLACE VIEW tmp_user_3 AS ' || V_SQL;
--DBMS_OUTPUT.PUT_LINE(V_SQL);
EXECUTE IMMEDIATE V_SQL;
END;
----------------執行存儲過程
BEGIN
P_tmp_user_2;
END;
----------------查看結果
SELECT * FROM tmp_user_3;
----------------第二部分測試數據
INSERT INTO tmp_user_2 VALUES(1003, 'M2',7);
INSERT INTO tmp_user_2 VALUES(1004, 'M5',8);
COMMIT;
----------------執行存儲過程
BEGIN
P_tmp_user_2;
END;
----------------查看結果
SELECT * FROM tmp_user_3;
----------------
其餘 :
1、橫表和縱表
橫表:一般指咱們平時在數據庫中創建的表,是一種普通的建表方式。
(主鍵、字段一、字段2......)如:時間、客戶ID,基本通話費、漫遊通話費,國內長途費、國際長途費....。
縱表:通常很少見,在表結構不肯定的時候,如需增長字段的狀況下的一種建表方式。
2、執行效率
橫表:後臺數據庫管理員操做簡單,直觀,清晰可見,一目瞭然。但若要給橫表中添加一個或者多個字段,就須重建表結構。
縱表:對於橫表的弊端,縱表中只須要添加一條記錄,就能夠添加一個字段,所消耗的代價遠比橫表小。可是縱表的對於數據描述不是很清晰,並且會形成數據庫數量不少。在查詢的時候用到group等函數會大大下降執行效率。縱表的初始映射要慢一些,縱表的變動的映射可能要快一些,若是隻是改變了單個字段時,畢竟橫表字段比縱表要多不少。
3、轉換
1.在平時的開發過程當中,可能會遇到字段的添加或者更好的維護和管理大數據量的表,就 會涉及到縱表和橫表之間的轉換。
2.把不容易改動表結構的設計成橫表,把容易常常改動不肯定的表結構設計成縱表。
舉例:
注:DECODE函數是ORACLE PL/SQL的功能強大的函數之一,目前還只有ORACLE公司的SQL提供了此函數,DECODE(value,if1,then1,if2,then2,if3,then3,...,else),表示若是value等於if1時,DECODE函數的結果返回then1,...,若是不等於任何一個if值,則返回else。
sign函數:在數學和計算機運算中,其功能是取某個數的符號(正或負): 當x≥0,sign(x)=1; 當x<0, sign(x)=-1;
縱錶轉橫表
- 縱表結構: TEST_Z2H
- FNAME FTYPE FVALUE
- 員工 zaocan 10
- 員工 zhongcan 20
- 員工 wancan 5
-
- 轉換後的表結構:
- FNAME ZAOCAN_VALUE ZHONGCAN_VALUE WANCAN_VALUE
- 員工 10 20 5
-
- 縱錶轉橫表SQL示例:
- SELECT FNAME,
- SUM(DECODE(FTYPE,'zaocan',FVALUE,0)) AS ZAOCAN_VALUE,
- SUM(DECODE(FTYPE,'zhongcan',FVALUE,0)) AS ZHONGCAN_VALUE,
- SUM(DECODE(FTYPE,'wancan',FVALUE,0)) AS WANCAN_VALUE
- FROM TEST_Z2H
- GROUP BY FNAME;
橫錶轉縱表
- 橫表結構: TEST_H2Z
- ID 姓名 語文 數學 英語
- 1 張三 80 90 70
- 2 李四 90 85 95
- 3 王五 88 75 90
-
- 轉換後的表結構:
- ID 姓名 科目 成績
- 1 張三 語文 80
- 2 張三 數學 90
- 3 張三 英語 70
- 4 李四 語文 90
- 5 李四 數學 80
- 6 李四 英語 99
- 7 王五 語文 85
- 8 王五 數學 96
- 9 王五 英語 88
- 橫錶轉縱表SQL示例:
- SELECT 姓名,'語文' AS 科目,語文 AS 成績 FROM TEST_H2Z UNION ALL
- SELECT 姓名,'數學' AS 科目,數學 AS 成績 FROM TEST_H2Z UNION ALL
- SELECT 姓名,'英語' AS 科目,英語 AS 成績 FROM TEST_H2Z
- ORDER BY 姓名,科目 DESC;
4、這裏有一篇用另外一種方式實現轉換並且帶和值查詢的博文:
http://exceptioneye.iteye.com/blog/1153345
橫表就是普通的建表方式,如一個表結構爲:
主鍵、字段一、字段二、字段3。。。
若是變成縱表後,則表結構爲:
主鍵、字段代碼、字段值。
而字段代碼則爲字段一、字段二、字段3。
縱表對從數據庫到內存的映射效率是有影響的,但細一點說也要一分爲二:
縱表的初始映射要慢一些;
縱表的變動的映射可能要快一些,若是隻是改變了單個字段時,畢竟橫表字段比縱表要多不少。
橫表的好處是清晰可見,一目瞭然,可是有一個弊端,若是如今要把這個表加一個字段,那麼就必須重建表結構。對於這種狀況,在縱表中只須要添加一條記錄,就能夠添加一個字段,所消耗的代價遠比橫表小,可是縱表的對於數據描述不是很清晰,並且會形成數據庫數量不少,二者利弊在於此。因此,應 該把不容易改動表結構的設計成橫表,把容易常常改動不肯定的表結構設計成縱表。
測試例子:
create table a(name varchar2(12),
math number,
englist number,chinese number);
插入兩行記錄:
張三 85 90 95
李四 90 85 86
轉行查詢語句:
- SELECT flag, MAX(李四) AS 李四, MAX(張三) AS 張三
- FROM (SELECT decode(NAME, '李四', fensu) as 李四,
- decode(NAME, '張三', fensu) AS 張三,
- flag
- FROM (SELECT a.NAME, a.math AS fensu, 'math' AS flag
- FROM a
- UNION ALL
- SELECT a.NAME, a.englist AS fensu, 'englist' AS flag
- FROM a
- UNION ALL
- SELECT a.NAME, a.chinese AS fensu, 'chinese' AS flag FROM a) b
- ORDER BY NAME, flag, fensu)
- GROUP BY flag
現有emp和dept表
EMP
empno number(4)
ename varchar2(10)
job varchar2(9)
mgr number(4)
hiredate date
sal number(7,2)
comm number(7,2)
deptno number(2)
DEPT
deptno number(2)
dname varchar2(14)
loc varchar2(13)
統計不一樣部門和工做的員工的總工資
實現橫標轉換爲縱表
decode實現
- select d.dname dname,
- sum(decode(e.job, 'CLERK', e.sal, 0)) CLERK,
- sum(decode(e.job, 'SALESMAN', e.sal, 0)) SALESMAN,
- sum(decode(e.job, 'ANALYST', e.sal, 0)) ANALYST,
- sum(decode(e.job, 'MANAGER', e.sal, 0)) MANAGER,
- sum(decode(e.job, 'PRESIDENT', e.sal, 0)) PRESIDENT
- from emp e
- join dept d
- on e.deptno = d.deptno
- group by d.dname;
-
-
- case when實現
- select d.dname dname,
- sum(
- case e.job
- when 'CLERK' then e.sal
- else 0
- end
- ) CLERK,
- sum(
- case e.job
- when 'SALESMAN' then e.sal
- else 0
- end
- ) SALESMAN,
- sum(
- case e.job
- when 'PRESIDENT' then e.sal
- else 0
- end
- ) PRESIDENT,
- sum(
- case e.job
- when 'MANAGER' then e.sal
- else 0
- end
- ) MANAGER,
- sum(
- case e.job
- when 'ANALYST' then e.sal
- else 0
- end
- ) ANALYST
- from emp e
- join dept d
- on e.deptno = d.deptno
- group by d.dname;
-
-
- 帶合計項的
- select d.dname dname,
- sum(decode(e.job, 'CLERK', e.sal, 0)) CLERK,
- sum(decode(e.job, 'SALESMAN', e.sal, 0)) SALESMAN,
- sum(decode(e.job, 'ANALYST', e.sal, 0)) ANALYST,
- sum(decode(e.job, 'MANAGER', e.sal, 0)) MANAGER,
- sum(decode(e.job, 'PRESIDENT', e.sal, 0)) PRESIDENT
- from emp e
- join dept d on e.deptno = d.deptno
- group by d.dname
- union
- select '總計' dname,
- sum(decode(e.job, 'CLERK', e.sal, 0)) CLERK,
- sum(decode(e.job, 'SALESMAN', e.sal, 0)) SALESMAN,
- sum(decode(e.job, 'ANALYST', e.sal, 0)) ANALYST,
- sum(decode(e.job, 'MANAGER', e.sal, 0)) MANAGER,
- sum(decode(e.job, 'PRESIDENT', e.sal, 0)) PRESIDENT
- from emp e
- join dept d2 on e.deptno = d2.deptno
-----------
SQL(橫表和縱表)行列轉換,PIVOT與UNPIVOT的區別和使用方法舉例,合併列的例子
使用過SQL Server 2000的人都知道,要想實現行列轉換,必須綜合利用聚合函數和動態SQL,具體實現起來須要必定的技巧,而在SQL Server 2005中,使用新引進的關鍵字PIVOT/UNPIVOT,則能夠很容易的實現行列轉換的需求。
在本文中咱們將經過兩個簡單的例子詳細講解PIVOT和UNPIVOT的用法。
PIVOT是行轉列,用法以下:
假如表結構以下:
id name quarter profile
1 a 1 1000
1 a 2 2000
1 a 3 4000
1 a 4 5000
2 b 1 3000
2 b 2 3500
2 b 3 4200
2 b 4 5500
----------------------------------------------
使用PIVOT將四個季度的利潤轉換成橫向顯示:
select id,name,
[1] as "一季度",[2] as "二季度",[3] as "三季度",[4] as "四季度"
from test
pivot
(
sum(profile)
for quarter in ([1],[2],[3],[4])
)
as pvt
-----------------------------------------------
得出的結果以下:
id name 一季度 二季度 三季度 四季度
1 a 1000 2000 4000 5000
2 b 3000 3500 4200 5500
========================================================================================
UNPIVOT是列轉行,用法以下:
假如表結構以下:
id name Q1 Q2 Q3 Q4
1 a 1000 2000 4000 5000
2 b 3000 3500 4200 5500
-----------------------------------------------
使用UNPIVOT,將同一行中四個季度的列數據轉換成四行數據:
select id,name,quarter,profile
from test
unpivot
(
profile
for quarter in ([Q1],[Q2],[Q3],[Q4])
)
as unpvt
-----------------------------------------------
得出的結果以下:
id name quarter profile
1 a Q1 1000
1 a Q2 2000
1 a Q3 4000
1 a Q4 5000
2 b Q1 3000
2 b Q2 3500
2 b Q3 4200
2 b Q4 5500
------------------------------------------------------------------------------
ORACLE縱向錶轉換爲橫向表寫法
設存在以下縱向表,第一列爲id(多是某個業務數據的id),第二列爲類型,第三列爲類型對應的值,以下圖:
如上表,存在2,3,4三種類型,其中業務數據ID爲1的三種類型都有值,業務數據ID爲2的三種類型都有值,業務數據ID爲3的只有類型2和3有值,如今要把縱向表橫過來顯示,能夠採用以下代碼:
- -- =========================================================
- -- 縱向表變橫向表:
- -- 1. 轉換類型,類型的值必須是整數,且不等於0,即0沒有意義,0能夠表示爲空
- -- =========================================================
- SELECT
- t.id,
- SUM(DECODE(t.code, 2, 2, 0)) "第二項", -- 若是該行類型爲2則就是2,其它的都爲0
- SUM(DECODE(t.code, 3, 3, 0)) "第三項",
- SUM(decode(t.code, 4, 4, 0)) "第四項"
- FROM ttt t WHERE t.id=1 GROUP BY t.id;
- -- =========================================================
- -- 縱向表變橫向表:
- -- 1. 轉換類型對應的數據,且數據須要是數值,且0沒有意義,即0能夠表示爲空
- -- =========================================================
- SELECT
- t.id,
- SUM(DECODE(t.code, 2, t.val, 0)) "第二項", -- 若是該行類型爲2則顯示2類型對應的值DECODE,不然都顯示0
- SUM(DECODE(t.code, 3, t.val, 0)) "第三項",
- SUM(DECODE(t.code, 4, t.val, 0)) "第四項"
- FROM ttt t GROUP BY t.id;
----------------------------------------------------------------------------------------------------------------------------------------
oracle合併列的函數wm_concat的使用詳解
oracle wm_concat(column)函數使咱們常常會使用到的,下面就教您如何使用oracle wm_concat(column)函數實現字段合併,若是您對oracle wm_concat(column)函數使用方面感興趣的話,不妨一看。
shopping:
-----------------------------------------
u_id goods num
------------------------------------------
1 蘋果 2
2 梨子 5
1 西瓜 4
3 葡萄 1
3 香蕉 1
1 橘子 3
=======================
想要的結果爲:
--------------------------------
u_id goods_sum
____________________
1 蘋果,西瓜,橘子
2 梨子
3 葡萄,香蕉
---------------------------------
1.select u_id, wmsys.wm_concat(goods) goods_sum 2. 3.from shopping 4. 5.group by u_id
想要的結果2:
--------------------------------
u_id goods_sum
____________________
1 蘋果(2斤),西瓜(4斤),橘子(3斤)
2 梨子(5斤)
3 葡萄(1斤),香蕉(1斤)
---------------------------------
使用oracle wm_concat(column)函數實現:
select u_id, wmsys.wm_concat(goods || '(' || num || '斤)' ) goods_sum
from shopping
group by u_id
mysql---group_concat
- 經過sql作數據透視表,數據庫錶行列轉換(pivot和Unpivot用法)(一)
在mssql中你們都知道可使用pivot來統計數據,實現像excel的透視表功能 一.MSsqlserver中咱們一般的用法 1.Sqlserver數據庫測試 ---建立測試表 Create tab ...
- SQL Server中行列轉換 Pivot UnPivot
SQL Server中行列轉換 Pivot UnPivot PIVOT用於將列值旋轉爲列名(即行轉列),在SQL Server 2000能夠用聚合函數配合CASE語句實現 PIVOT的通常語法是:PI ...
- sql 行專列 列轉行 普通行列轉換
轉載:http://www.cnblogs.com/newwind521/archive/2010/11/25/1887203.html sql 行專列 列轉行 普通行列轉換 /* 標題:普通行列轉換 ...
- SQL SERVER 合併重複行,行列轉換
引用自:http://www.cnblogs.com/love-summer/archive/2012/03/27/2419778.html sql server2000 裏面如何實現oracle10 ...
- SQL中行列轉換Pivot
--建表 ),課程 ),分數 int) --插入數據 ) ) ) ) ) ) 1.靜態行轉列(肯定有哪些列) select 姓名, end)語文, end)數學, end)物理 from tb gro ...
- 多列的行列轉換(PIVOT,UNPIVOT)
形式1 形式2 形式3 有時候可能會有這樣的需求: 將一張表的全部列名轉作爲數據的一列數據,將一列數據做爲整張表的列名 當列比較多時,只用PIVOT是解決不了的,通過研究,須要將UNPIVOT 和 P ...
- 行列轉換 pivot
select * from ( select isnull(c.type,'其餘') type,d from ( select ID,Record_code,code,day(thedate) d f ...
- sqlserver表分區與調優與行列轉換
轉自: http://www.cnblogs.com/knowledgesea/p/3696912.html http://www.open-open.com/lib/view/open1418462 ...
- 瑞麗的SQL-SQL Server的表旋轉(行列轉換)
所謂表旋轉,就是將表的行轉換爲列,或是將表的列轉換爲行,這是從SQL Server 2005開始提供的新技術.所以,若是但願使用此功能,需要將數據庫的兼容級別設置爲90.表旋轉在某些方面也是攻克了表的 ...