普通行列转换
假设有张学生成绩表(t)如下
Name Subject Result
张三 语文 73
张三 数学 83
张三 物理 93
李四 语文 74
李四 数学 84
李四 物理 94
想变成
姓名 语文 数学 物理
张三 73 83 93
李四 74 84 94
create table #t
(
Name varchar(10) ,
Subject varchar(10) ,
Result int
)
insert into #t(Name , Subject , Result) values('张三','语文','73')
insert into #t(Name , Subject , Result) values('张三','数学','83')
insert into #t(Name , Subject , Result) values('张三','物理','93')
insert into #t(Name , Subject , Result) values('李四','语文','74')
insert into #t(Name , Subject , Result) values('李四','数学','83')
insert into #t(Name , Subject , Result) values('李四','物理','93')
declare @sql varchar(8000)
set @sql = 'select Name as ' + '姓名'
select @sql = @sql + ' , sum(case Subject when ''' + Subject + ''' then Result end) [' + Subject + ']'
from (select distinct Subject from #t) as a
set @sql = @sql + ' from #t group by name'
exec(@sql)
drop table #t
--结果
姓名 数学 物理 语文
---------- ----------- ----------- -----------
李四 83 93 74
张三 83 93 73
----------------------------------------------------
如果上述两表互相换一下:即
姓名 语文 数学 物理
张三 73 83 93
李四 74 84 94
想变成
Name Subject Result
张三 语文 73
张三 数学 83
张三 物理 93
李四 语文 74
李四 数学 84
李四 物理 94
create table #t
(
姓名 varchar(10) ,
语文 int ,
数学 int ,
物理 int
)
insert into #t(姓名 , 语文 , 数学 , 物理) values('张三',73,83,93)
insert into #t(姓名 , 语文 , 数学 , 物理) values('李四',74,84,94)
select 姓名 as Name,'语文' as Subject,语文 as Result from #t union
select 姓名 as Name,'数学' as Subject,数学 as Result from #t union
select 姓名 as Name,'物理' as Subject,物理 as Result from #t
order by 姓名 desc
drop table #t
--结果
Name Subject Result
---------- ------- -----------
张三 数学 83
张三 物理 93
张三 语文 73
李四 数学 84
李四 物理 94
李四 语文 74
(所影响的行数为 6 行)
--带符号合并行列转换
--有表t,其数据如下:
a b
1 1
1 2
1 3
2 1
2 2
3 1
--如何转换成如下结果:
a b
1 1,2,3
2 1,2
3 1
create table tb
(
a int,
b int
)
insert into tb(a,b) values(1,1)
insert into tb(a,b) values(1,2)
insert into tb(a,b) values(1,3)
insert into tb(a,b) values(2,1)
insert into tb(a,b) values(2,2)
insert into tb(a,b) values(3,1)
go
if object_id('pubs..f_hb') is not null
drop function f_hb
go
--创建一个合并的函数
create function f_hb(@a int)
returns varchar(8000)
as
begin
declare @str varchar(8000)
set @str = ''
select @str = @str + ',' + cast(b as varchar) from tb where a = @a
set @str = right(@str , len(@str) - 1)
return(@str)
End
go
--调用自定义函数得到结果:
select distinct a ,dbo.f_hb(a) as b from tb
drop table tb
--结果
a b
----------- ------
1 1,2,3
2 1,2
3 1
(所影响的行数为 3 行)
多个前列的合并
数据的原始状态如下:
ID PR CON OP SC
001 p c 差 6
001 p c 好 2
001 p c 一般 4
002 w e 差 8
002 w e 好 7
002 w e 一般 1
===========================
用SQL语句实现,变成如下的数据
ID PR CON OPS
001 p c 差(6),好(2),一般(4)
002 w e 差(8),好(7),一般(1)
if object_id('pubs..tb') is not null
drop table tb
go
create table tb
(
id varchar(10),
pr varchar(10),
con varchar(10),
op varchar(10),
sc int
)
insert into tb(ID,PR,CON,OP,SC) values('001', 'p', 'c', '差', 6)
insert into tb(ID,PR,CON,OP,SC) values('001', 'p', 'c', '好', 2)
insert into tb(ID,PR,CON,OP,SC) values('001', 'p', 'c', '一般', 4)
insert into tb(ID,PR,CON,OP,SC) values('002', 'w', 'e', '差', 8)
insert into tb(ID,PR,CON,OP,SC) values('002', 'w', 'e', '好', 7)
insert into tb(ID,PR,CON,OP,SC) values('002', 'w', 'e', '一般', 1)
go
if object_id('pubs..test') is not null
drop table test
go
select ID,PR,CON , OPS = op + '(' + cast(sc as varchar(10)) + ')' into test from tb
--创建一个合并的函数
if object_id('pubs..f_hb') is not null
drop function f_hb
go
create function f_hb(@id varchar(10),@pr varchar(10),@con varchar(10))
returns varchar(8000)
as
begin
declare @str varchar(8000)
set @str = ''
select @str = @str + ',' + cast(OPS as varchar) from test where id = @id and @pr = pr and @con = con
set @str = right(@str , len(@str) - 1)
return(@str)
End
go
--调用自定义函数得到结果:
select distinct id ,pr , con , dbo.f_hb(id,pr,con) as OPS from test
drop table tb
drop table test
--结果
id pr con OPS
---------- ---------- ---------- -------------------
001 p c 差(6),好(2),一般(4)
002 w e 差(8),好(7),一般(1)
(所影响的行数为 2 行)
create table b
(col varchar(20))
insert b values ('a')
insert b values ('b')
insert b values ('c')
insert b values ('d')
insert b values ('e')
declare @sql varchar(1024)
set @sql=''
select @sql=@sql+b.col+',' from (select col from b) as b
set @sql='select '''+@sql+''''
exec(@sql)
行列转换并取平均值
站名 年份 数据
AA 1986 23.5
AA 1987 25.6
AA 1988 23.0
BB 1986 21.0
BB 1987 22.0
BB 1988 22.7
CC 1986 21.8
CC 1987 23.0
CC 1988 21.8
......
我想写成这样的表:
序号 年份 AA BB CC ....平均
1 1986 23.5 21.0 21.8 ....22.1
2 1987 25.6 22.0 23.0 ....23.5
3 1988 23.0 22.7 21.8 ....22.5
create table #tab ([站名][char](10),[年份] [int],[数据] [decimal](18, 1))
insert #tab values('AA',1986,23.5)
insert #tab values('AA',1987,25.6)
insert #tab values('AA',1988,23.0)
insert #tab values('BB',1986,21.0)
insert #tab values('BB',1987,22.0)
insert #tab values('BB',1988,22.7)
insert #tab values('CC',1986,21.8)
insert #tab values('CC',1987,23.0)
insert #tab values('CC',1988,21.8)
declare @sql varchar(4000)
set @sql = 'select 年份 '
select @sql = @sql + ' , sum(case 站名 when '''+ 站名 +''' then 数据 end) ['+ 站名 +']'
from (select distinct 站名 from #tab) as a
set @sql = @sql + ', avg(数据) as 平均 from #tab group by 年份'
exec(@sql)
drop table #tab
年份 AA BB CC 平均
---- ----- ----- ----- ----------
1986 23.5 21.0 21.8 22.100000
1987 25.6 22.0 23.0 23.533333
1988 23.0 22.7 21.8 22.500000
--另外的做法
declare @sql varchar(8000)
set @sql='select 年份'
select @sql=@sql+',['+站名+']=max(case 站名 when '''+站名+''' then 数据 end)' from 表 group by 站名 order by 站名
set @sql=@sql+',avg(数据) as 平均 from 表 group by 年份'
exec(@sql)
declare @name varchar(1000)
set @name=''
select @name=@name+',max(case when 站名='''+站名+''' then 數據 end) ['+站名+']' from test group by 站名 order by 站名
select @name='select identity(int,1,1)序號,年份'+@name+',cast(avg (數據) as decimal(15,1)) 平均 into #a from test group by 年份 order by 1 select * from #a'
exec (@name)
/*
序號年份AABBCC平均
1198623.521.021.822.1
2198725.622.023.023.5
3198823.022.721.822.5
*/
現有用SQL查詢出的數據如下,請問如何寫SQL才能得到轉換後的結果呢
DValue
C10
C21
C320.00
C110
C211
C312
轉換後
C1C2C3
0120
101112
--創建測試環境
Create Table 表
(ID Varchar(10),
Value Int)
--插入數據
Insert 表 Select 'C1',0
Union All Select 'C2',1
Union All Select 'C3',20
Union All Select 'C1',10
Union All Select 'C2',11
Union All Select 'C3',12
GO
--測試
--借用臨時表
Select ID2 = Identity(Int, 1, 1), * Into #T From 表
--如果ID是固定三個
Select
Max(Case ID When 'C1' Then Value Else 0 End) As C1,
Max(Case ID When 'C2' Then Value Else 0 End) As C2,
Max(Case ID When 'C3' Then Value Else 0 End) As C3
From
(Select OrderID = (Select Count(ID2) From #T Where ID = A.ID And ID2 <= A.ID2), * From #T A) B
Group By
OrderID
--如果ID不是固定三個
Declare @S Varchar(8000)
Select @S = ''
Select @S = @S + ', Max(Case ID When ''' + ID + ''' Then Value Else 0 End) As [' + ID + ']'
From 表 Group By ID
Select @S= 'Select ' + Stuff(@S, 1, 1, '') + ' From (Select OrderID = (Select Count(ID2) From #T Where ID = A.ID And ID2 <= A.ID2), * From #T A) B Group By OrderID '
EXEC(@S)
Drop Table #T
GO
--刪除測試環境
Drop Table 表
--結果
/*
C1C2C3
0120
101112
*/
表 department
departmenid(部门ID) parentid(父部门ID)
1 0
2 1
3 1
4 2
5 2
6 3
7 3
8 7
我查询部门ID ,张三对应的部门ID为8 ,如何查出张三的所有部门ID(包括父部门ID),如8,7,3,1
--建立測試環境
Create Table department
(departmenid Int,
parentid Int)
Insert department Select 60, null
Union All Select 1, 0
Union All Select 2, 1
Union All Select 3, 1
Union All Select 4, 2
Union All Select 5, 2
Union All Select 6, 3
Union All Select 7, 3
Union All Select 8, 7
GO
--建立函數
Create Function F_GetParent(@departmenid Int)
Returns @Tree Table (departmenid Int, parentid Int)
As
Begin
Insert @Tree Select * From department Where departmenid = @departmenid
While @@Rowcount > 0
Insert @Tree Select A.* From department A Inner Join @Tree B On A.departmenid = B.parentid And A.departmenid Not In (Select departmenid From @Tree) Where A.parentid Is Not Null
Return
End
GO
--測試
Select departmenid From dbo.F_GetParent(8) Order By parentid
GO
--刪除測試環境
Drop Table department
Drop Function F_GetParent
--結果
/*
departmenid
1
3
7
8
*/
我写的一种方法:
Create Function F_GetParent(@departmenid Int)
Returns @Tree Table (departmenid Int, parentid Int)
As
Begin
declare @i varchar(100)
While @departmenid <>0
begin
select @i=parentid From department Where departmenid = @departmenid
Insert @Tree Select * From department Where departmenid = @departmenid
set @departmenid =@i
end
Return
End
--創建存儲過程
Create ProceDure SP_GetParent(@departmenid Int)
As
Begin
Select * Into #Tree From department Where departmenid = @departmenid
While @@Rowcount > 0
Insert #Tree Select A.* From department A Inner Join #Tree B On A.departmenid = B.parentid And A.departmenid Not In (Select departmenid From #Tree) Where A.parentid Is Not Null
Select departmenid From #Tree Order By parentid
Drop Table #Tree
End
GO
--測試
EXEC SP_GetParent 8
GO
--刪除測試環境
Drop Table department
Drop ProceDure SP_GetParent
--結果
/*
departmenid
1
3
7
8
*/
这里有一个递归的列子:
create table ta (项目 varchar(20),上级项目 varchar(20),num int)
insert ta
select 'A ', ' ' ,100 union all
select 'B ', 'A ' ,200 union all
select 'C ', 'B ' ,300 union all
select 'D ', 'B ' ,400 union all
select 'E ', 'C ' ,500 union all
select 'F ', 'D ' ,600 union all
select 'H ', 'E ' ,700 union all
select 'G ', 'F ' ,800
如果要显示上级的项目:
create function roy_f(@项目 varchar(20))
returns varchar(100)
as
begin
declare @上级项目 varchar(20)
select @上级项目=上级项目 from ta where 项目=@项目
return case when @上级项目 is null then null
else isnull(dbo.roy_f(@上级项目)+ '- ', ' ')+@项目 end
end
go
select 项目,关系=dbo.roy_f(项目) from ta
id num
01 0
01 1
01 -1
希望得到如下结果
id n1 n2 n3
01 0 1 -1
create table #a (id varchar(10),num int)
insert into #a
select '01',-4
union all select '01',0
union all select '01',61
union all select '02',-5
union all select '02',16
union all select '02',8
select * from #a
drop table #a
Select ID2 = Identity(Int, 1, 1), * Into #T From #a
--1
declare @sql varchar(1000)
set @sql='select id'
select @sql=@sql+',max(case when OrderID='''+ cast(OrderID as varchar(10))+'''then num end )as num'+cast(OrderID as varchar(10)) from (select distinct OrderID from (Select OrderID = (Select Count(ID2) From #T Where ID = A.ID And ID2 <= A.ID2), * From #T A)b)c
select @sql=@sql+' from (Select OrderID = (Select Count(ID2) From #T Where ID = A.ID And ID2 <= A.ID2), * From #T A)b group by id'
print @sql
exec(@sql)
--2
declare @T int,@Max int,@sql varchar(1000)
select top 1 @Max=count(1),@T=1 from #t group by id order by count(1) desc
set @sql=''
while (@T<=@Max)
begin
select @sql=@sql+',[n'+cast(@T as varchar(100))+']=max(case OrderID when '''+cast(@T as varchar(100))+''' then num end)'
set @T=@T+1
end
select @sql='select id'+@sql+' from (Select OrderID = (Select Count(ID2) From #T Where ID = A.ID And ID2 <= A.ID2), * From #T A)b group by id'
print @sql
exec(@sql)
mysql存储过程用法
DELIMITER $$
DROP PROCEDURE IF EXISTS `test`.`proc_sms2`$$
CREATE PROCEDURE proc_sms2
(
in qudao varchar(100) ,
in ruleid varchar(100)
)
BEGIN
DROP TABLE IF EXISTS NEWTT;
select qudao;
SET @SQL1='';
select @SQL1:= CONCAT(@SQL1,' , sum(case rulefield when ''' , rulefield , '''
then fieldvalue end) AS `' , rulefield , '`')
from (select distinct rulefield from sms) as a;
SET @v_sql = CONCAT('CREATE TABLE NEWTT AS select max(qudao) as 渠道, max(ruleid) as 策略 ',@sql1 , ',max(operate) as 操作, max(priority) as 优先级 ,flag from sms where qudao=/'',qudao,'/' group by flag');
PREPARE stmt2 FROM @v_sql;
EXECUTE stmt2;
END$$
DELIMITER ;
call proc_sms2("kjava","rule1")
select * from NEWTT
---------------------------------触发器
-
SQL code
-
IF OBJECT_ID ( ' A ' ) IS NOT NULL
DROP TABLE A
IF OBJECT_ID ( ' B ' ) IS NOT NULL
DROP TABLE B
IF OBJECT_ID ( ' c ' ) IS NOT NULL
DROP TABLE c
GO
CREATE TABLE A( id int ,坐标x DECIMAL ( 19 , 5 ),w_id int )
go
insert A SELECT
01 , 39.72555 , 01 UNION ALL SELECT
02 , 39.58586 , 02
CREATE TABLE B( id int ,坐标x DECIMAL ( 19 , 5 ),巡检时间 datetime )
go
insert B SELECT
01 , 39.12 , ' 2009-8-1 ' UNION ALL SELECT
02 , 39.78586 , ' 2009-8-3 ' UNION ALL SELECT
02 , 39.53586 , ' 2009-8-1 ' UNION ALL SELECT
02 , 39.483246 , ' 2009-8-22 ' UNION ALL SELECT
02 , 39.348586 , ' 2009-8-22 '
CREATE TABLE c( id int ,开始时间 datetime ,结束时间 datetime )
go
insert c SELECT
01 , ' 2009-8-1 ' , ' 2009-8-3 ' UNION ALL SELECT
02 , ' 2009-8-20 ' , ' 2009-8-23 '
go
if object_id ( ' gg ' ) is not null drop trigger gg
go
create trigger gg on a
for delete
as
if not exists ( select * from inserted) and exists ( select * from deleted)
begin
delete b from deleted de where de.id = b.id
delete c from deleted de where de.id = c.id
end
go
select * from b
select * from c -- 原始表
delete a where id = 02
select * from b -- 触发后表
select * from c
id 坐标x 巡检时间
-- --------- --------------------------------------- -----------------------
1 39.12000 2009 - 08 - 01 00 : 00 : 00.000
2 39.78586 2009 - 08 - 03 00 : 00 : 00.000
2 39.53586 2009 - 08 - 01 00 : 00 : 00.000
2 39.48325 2009 - 08 - 22 00 : 00 : 00.000
2 39.34859 2009 - 08 - 22 00 : 00 : 00.000
( 5 行受影响)
id 开始时间 结束时间
-- --------- ----------------------- -----------------------
1 2009 - 08 - 01 00 : 00 : 00.000 2009 - 08 - 03 00 : 00 : 00.000
2 2009 - 08 - 20 00 : 00 : 00.000 2009 - 08 - 23 00 : 00 : 00.000
( 2 行受影响)
( 4 行受影响)
( 1 行受影响)
( 1 行受影响)
id 坐标x 巡检时间
-- --------- --------------------------------------- -----------------------
1 39.12000 2009 - 08 - 01 00 : 00 : 00.000
( 1 行受影响)
id 开始时间 结束时间
-- --------- ----------------------- -----------------------
1 2009 - 08 - 01 00 : 00 : 00.000 2009 - 08 - 03 00 : 00 : 00.000
---------------------------------------游标
drop table tb
CREATE TABLE tb(col1 varchar(10),col2 int)
INSERT tb SELECT 'a',1
UNION ALL SELECT 'a',2
UNION ALL SELECT 'b',1
UNION ALL SELECT 'b',2
UNION ALL SELECT 'b',3
--合并处理
--定义结果集表变量
DECLARE @t TABLE(col1 varchar(10),col2 varchar(100))
--定义游标并进行合并处理
DECLARE tb CURSOR LOCAL
FOR
SELECT col1,col2 FROM tb ORDER BY col1,col2
DECLARE @col1_old varchar(10),@col1 varchar(10),@col2 int,@s varchar(100)
OPEN tb
FETCH tb INTO @col1,@col2 <====>FETCH next from tb INTO @col1,@col2
print @col1
print @col2
SELECT @col1_old=@col1,@s=''
WHILE @@FETCH_STATUS=0
BEGIN
IF @col1=@col1_old
SELECT @s=@s+','+CAST(@col2 as varchar)
ELSE
BEGIN
INSERT @t VALUES(@col1_old,STUFF(@s,1,1,''))
SELECT @s=','+CAST(@col2 as varchar),@col1_old=@col1
END
FETCH tb INTO @col1,@col2
END
INSERT @t VALUES(@col1_old,STUFF(@s,1,1,''))
CLOSE tb
DEALLOCATE tb