源于一个想法,需要写一个SQL语句来实现,但没有成功。
即:把表2中的一行数据,作为表1新增的一列显示出来。(行列的数目是对应的)举例如下--------表1内容:
ENFIELD CHNAME
A 序号1
B 序号2
C 序号3
D 序号4
E 序号5
... ...
------------表2内容:
A B C D E ......
值1 值2 值3 值4 值5 ......------------要求SQL查询得到如下效果:把表2中的一行数据,作为表1新增的一列(VALUES)显示出来。 ENFIELD CHNAME VALUES
A 序号1 值1
B 序号2 值2
C 序号3 值3
D 序号4 值4
E 序号5 值5
... ... ...----------------------在此向各位请教。 如果用SQL_Server能实现,那么用Oracle又如何写呢?多谢了!
即:把表2中的一行数据,作为表1新增的一列显示出来。(行列的数目是对应的)举例如下--------表1内容:
ENFIELD CHNAME
A 序号1
B 序号2
C 序号3
D 序号4
E 序号5
... ...
------------表2内容:
A B C D E ......
值1 值2 值3 值4 值5 ......------------要求SQL查询得到如下效果:把表2中的一行数据,作为表1新增的一列(VALUES)显示出来。 ENFIELD CHNAME VALUES
A 序号1 值1
B 序号2 值2
C 序号3 值3
D 序号4 值4
E 序号5 值5
... ... ...----------------------在此向各位请教。 如果用SQL_Server能实现,那么用Oracle又如何写呢?多谢了!
a 值1
b 值2
c 值3
c 值4select 'a' col1,a col2 from tb2
union all
select 'b' col1,b col2 from tb2
...
...然后再join就行.
标题:普通行列转换(version 2.0)
作者:爱新觉罗.毓华
时间:2008-03-09
地点:广东深圳
说明:普通行列转换(version 1.0)仅针对sql server 2000提供静态和动态写法,version 2.0增加sql server 2005的有关写法。问题:假设有张学生成绩表(tb)如下:
姓名 课程 分数
张三 语文 74
张三 数学 83
张三 物理 93
李四 语文 74
李四 数学 84
李四 物理 94
想变成(得到如下结果):
姓名 语文 数学 物理
---- ---- ---- ----
李四 74 84 94
张三 74 83 93
-------------------
*/create table tb(姓名 varchar(10) , 课程 varchar(10) , 分数 int)
insert into tb values('张三' , '语文' , 74)
insert into tb values('张三' , '数学' , 83)
insert into tb values('张三' , '物理' , 93)
insert into tb values('李四' , '语文' , 74)
insert into tb values('李四' , '数学' , 84)
insert into tb values('李四' , '物理' , 94)
go--SQL SERVER 2000 静态SQL,指课程只有语文、数学、物理这三门课程。(以下同)
select 姓名 as 姓名 ,
max(case 课程 when '语文' then 分数 else 0 end) 语文,
max(case 课程 when '数学' then 分数 else 0 end) 数学,
max(case 课程 when '物理' then 分数 else 0 end) 物理
from tb
group by 姓名--SQL SERVER 2000 动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)
declare @sql varchar(8000)
set @sql = 'select 姓名 '
select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
from (select distinct 课程 from tb) as a
set @sql = @sql + ' from tb group by 姓名'
exec(@sql) --SQL SERVER 2005 静态SQL。
select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b--SQL SERVER 2005 动态SQL。
declare @sql varchar(8000)
select @sql = isnull(@sql + '],[' , '') + 课程 from tb group by 课程
set @sql = '[' + @sql + ']'
exec ('select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b')---------------------------------/*
问题:在上述结果的基础上加平均分,总分,得到如下结果:
姓名 语文 数学 物理 平均分 总分
---- ---- ---- ---- ------ ----
李四 74 84 94 84.00 252
张三 74 83 93 83.33 250
*/--SQL SERVER 2000 静态SQL。
select 姓名 姓名,
max(case 课程 when '语文' then 分数 else 0 end) 语文,
max(case 课程 when '数学' then 分数 else 0 end) 数学,
max(case 课程 when '物理' then 分数 else 0 end) 物理,
cast(avg(分数*1.0) as decimal(18,2)) 平均分,
sum(分数) 总分
from tb
group by 姓名--SQL SERVER 2000 动态SQL。
declare @sql varchar(8000)
set @sql = 'select 姓名 '
select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
from (select distinct 课程 from tb) as a
set @sql = @sql + ' , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名'
exec(@sql) --SQL SERVER 2005 静态SQL。
select m.* , n.平均分 , n.总分 from
(select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b) m,
(select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
where m.姓名 = n.姓名--SQL SERVER 2005 动态SQL。
declare @sql varchar(8000)
select @sql = isnull(@sql + ',' , '') + 课程 from tb group by 课程
exec ('select m.* , n.平均分 , n.总分 from
(select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b) m ,
(select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
where m.姓名 = n.姓名')drop table tb ------------------
------------------/*
问题:如果上述两表互相换一下:即表结构和数据为:
姓名 语文 数学 物理
张三 74 83 93
李四 74 84 94
想变成(得到如下结果):
姓名 课程 分数
---- ---- ----
李四 语文 74
李四 数学 84
李四 物理 94
张三 语文 74
张三 数学 83
张三 物理 93
--------------
*/create table tb(姓名 varchar(10) , 语文 int , 数学 int , 物理 int)
insert into tb values('张三',74,83,93)
insert into tb values('李四',74,84,94)
go--SQL SERVER 2000 静态SQL。
select * from
(
select 姓名 , 课程 = '语文' , 分数 = 语文 from tb
union all
select 姓名 , 课程 = '数学' , 分数 = 数学 from tb
union all
select 姓名 , 课程 = '物理' , 分数 = 物理 from tb
) t
order by 姓名 , case 课程 when '语文' then 1 when '数学' then 2 when '物理' then 3 end--SQL SERVER 2000 动态SQL。
--调用系统表动态生态。
declare @sql varchar(8000)
select @sql = isnull(@sql + ' union all ' , '' ) + ' select 姓名 , [课程] = ' + quotename(Name , '''') + ' , [分数] = ' + quotename(Name) + ' from tb'
from syscolumns
where name! = N'姓名' and ID = object_id('tb') --表名tb,不包含列名为姓名的其它列
order by colid asc
exec(@sql + ' order by 姓名 ')--SQL SERVER 2005 动态SQL。
select 姓名 , 课程 , 分数 from tb unpivot (分数 for 课程 in([语文] , [数学] , [物理])) t--SQL SERVER 2005 动态SQL,同SQL SERVER 2000 动态SQL。--------------------
/*
问题:在上述的结果上加个平均分,总分,得到如下结果:
姓名 课程 分数
---- ------ ------
李四 语文 74.00
李四 数学 84.00
李四 物理 94.00
李四 平均分 84.00
李四 总分 252.00
张三 语文 74.00
张三 数学 83.00
张三 物理 93.00
张三 平均分 83.33
张三 总分 250.00
------------------
*/select * from
(
select 姓名 as 姓名 , 课程 = '语文' , 分数 = 语文 from tb
union all
select 姓名 as 姓名 , 课程 = '数学' , 分数 = 数学 from tb
union all
select 姓名 as 姓名 , 课程 = '物理' , 分数 = 物理 from tb
union all
select 姓名 as 姓名 , 课程 = '平均分' , 分数 = cast((语文 + 数学 + 物理)*1.0/3 as decimal(18,2)) from tb
union all
select 姓名 as 姓名 , 课程 = '总分' , 分数 = 语文 + 数学 + 物理 from tb
) t
order by 姓名 , case 课程 when '语文' then 1 when '数学' then 2 when '物理' then 3 when '平均分' then 4 when '总分' then 5 enddrop table tb
--> 生成测试数据: #tb1
if object_id('tempdb.dbo.#tb1') is not null drop table #tb1
create table #tb1 (ENFIELD varchar(1),CHNAME nvarchar(5))
insert into #tb1
select 'A','序号1' union all
select 'B','序号2' union all
select 'C','序号3' union all
select 'D','序号4' union all
select 'E','序号5'
--> liangCK小梁 于2008-07-26
--> 生成测试数据: #tb2
if object_id('tempdb.dbo.#tb2') is not null drop table #tb2
create table #tb2 (A nvarchar(3),B nvarchar(3),C nvarchar(3),D nvarchar(3),E nvarchar(3))
insert into #tb2
select '值1','值2','值3','值4','值5'select a.*,b.col2
from #tb1 a
left outer join
(
select 'a' col1,A col2 from #tb2
union all
select 'b' col1,B col2 from #tb2
union all
select 'c' col1,C col2 from #tb2
union all
select 'd' col1,D col2 from #tb2
union all
select 'e' col1,E col2 from #tb2
) b
on a.ENFIELD=b.col1/*
ENFIELD CHNAME col2
------- ------ ----
A 序号1 值1
B 序号2 值2
C 序号3 值3
D 序号4 值4
E 序号5 值5(5 行受影响)
*/
值1 值2 值3 值4 值5 ...... declare @t table(ENFIELD char , col2 char)
insert @t
select A,'值1' from 表2 union all
select B,'值2' from 表2 union all
select C,'值3' from 表2 union all
select D,'值4' from 表2 union all
select E,'值4' from 表2 select 表1.ENFIELD,表1.CHNAME,@t.col2 from 表1 left jion @t on 表[email protected]
DROP TABLE t1
GO
IF object_id('t2') IS NOT NULL
DROP TABLE t2
GOCREATE TABLE t1(id VARCHAR(10),name VARCHAR(10))
GO
INSERT t1 SELECT 'a','serial1'
UNION ALL SELECT 'b','serial2'
UNION ALL SELECT 'c','serial3'
UNION ALL SELECT 'd','serial4'
GOCREATE TABLE t2(a VARCHAR(10),b VARCHAR(10),c VARCHAR(10),d VARCHAR(10))
GO
INSERT t2 SELECT 'v1','v2','v3','v4'
GO
DECLARE @sql VARCHAR(8000)
SELECT @sql=ISNULL(@sql + ' UNION ALL ','') + 'SELECT id=''' + name + ''',x=(SELECT TOP 1 ' + name + ' FROM t2)' FROM syscolumns WHERE id=object_id('t2')
EXEC('SELECT a.id ENFIELD ,a.name CHNAME,b.x [VALUES] FROM t1 a INNER JOIN (' + @sql + ') b ON a.id=b.id')/*
a serial1 v1
b serial2 v2
c serial3 v3
d serial4 v4
*/
declare @t1 table(ENFIELD char(1), CHNAME varchar(10))
insert into @t1
select 'A', '序号1' union all
select 'B', '序号2' union all
select 'C', '序号3' union all
select 'D', '序号4' union all
select 'E', '序号5'declare @t2 table(A varchar(10), B varchar(10), C varchar(10), D varchar(10), E varchar(10))
insert into @t2
select '值1', '值2', '值3', '值4', '值5' select t1.*,
(select case when t1.ENFIELD='A' then t2.A
when t1.ENFIELD='B' then t2.B
when t1.ENFIELD='C' then t2.C
when t1.ENFIELD='D' then t2.D
when t1.ENFIELD='E' then t2.E end
from @t2 t2) [VALUES]
from @t1 t1
/*
ENFIELD CHNAME VALUES
A 序号1 值1
B 序号2 值2
C 序号3 值3
D 序号4 值4
E 序号5 值5
*/
A B C D E ......
值1 值2 值3 值4 值5 ......
-----------------------------其实我的表2有很多列啊。 我刚才数了一下,有73列。这73个,都要Union啊????
用
标题:普通行列转换(version 2.0)
作者:爱新觉罗.毓华 行列转换 然后在匹配
if object_id('t1') is not null
drop table t1
go
create table t1(ENFIELD char(1), CHNAME varchar(10))
insert into t1
select 'A', '序号1' union all
select 'B', '序号2' union all
select 'C', '序号3' union all
select 'D', '序号4' union all
select 'E', '序号5'if object_id('t2') is not null
drop table t2
go
create table t2(A varchar(10), B varchar(10), C varchar(10), D varchar(10), E varchar(10))
insert into t2
select '值1', '值2', '值3', '值4', '值5' declare @s varchar(8000)
set @s='select *, (select case ENFIELD'
select @s=@s + ' when '''+ENFIELD+''' then '+ENFIELD from t1set @s=@s+' end from t2) [values] from t1'exec(@s)/*
ENFIELD CHNAME VALUES
A 序号1 值1
B 序号2 值2
C 序号3 值3
D 序号4 值4
E 序号5 值5
*/
不能正确执行。
用10楼的方法,动态执行SQL,老是报错:
将 varchar 值 转换为数据类型为 int 的列时发生语法错误。
或
从字符串转换为 datetime 时发生语法错误。
但是实际上,我仔细查证,数据库字段内容都存储正确。----这一点非常奇怪。
郁闷。总的来说,非常感谢楼上的各位!!
需要前后进行联合的行集
1,列数一样
2,对应位置的列类型一致或可隐式转换。
比如
select 1 as id
union all
select 'x'
就会报错,第一行的select 1 as id确定的产生的结果集中 id为int
而第二个行集,产生的是varchar,它尝试将'x'转换为int所以报错select rtrim(1) as id
union all
select 'x'
这样就可以。
to 10楼 npkaida : 多谢!按照您提供的方法,再加上rtrim()函数,问题搞定!------非常感谢楼上的各位提供的动态SQL方法,今天一天学习了不少东西。多谢各位了!
-------
ENFIELD CHNAME VALUES
A 序号1 值1
B 序号2 值2
C 序号3 值3
D 序号4 值4
E 序号5 值5
... ... ...
在您写的SQL的基础上,我想做查询利用--想加上复杂的查询条件, 这样的SQL能否做到??如,我想做类似的查询,加上查询条件:
-----
... where (ENFIELD='A' and VALUES='值1') or (ENFIELD='C' and VALUES='值3')
根据查询条件,得到这样的结果:
------
ENFIELD CHNAME VALUES
A 序号1 值1
C 序号3 值3-----我能否做到?? 该如何拼写SQL呢? 谢谢。
if object_id('t1') is not null
drop table t1
go
create table t1(ENFIELD char(1), CHNAME varchar(10))
insert into t1
select 'A', '序号1' union all
select 'B', '序号2' union all
select 'C', '序号3' union all
select 'D', '序号4' union all
select 'E', '序号5'if object_id('t2') is not null
drop table t2
go
create table t2(A varchar(10), B varchar(10), C varchar(10), D varchar(10), E varchar(10))
insert into t2
select '值1', '值2', '值3', '值4', '值5' declare @s varchar(8000)
set @s=';with t as (select *, (select case ENFIELD'
select @s=@s + ' when '''+ENFIELD+''' then '+ENFIELD from t1set @s=@s+' end from t2) [values] from t1)'+
' select * from t where (ENFIELD=''A'' and [VALUES]=''值1'') or (ENFIELD=''C'' and [VALUES]=''值3'')'exec(@s)
to npkaida :运行提示信息:--- ';' 附近有语法错误。
5楼那个动态SQL
适合2000
GOCREATE TABLE dbo.T1
(
ID INT IDENTITY(1,1) NOT NULL
,ENFIELD NVARCHAR(10) NULL
,CHNAME NVARCHAR(10) NULL
,CONSTRAINT PK_T1 PRIMARY KEY (ID ASC)
)
INSERT INTO dbo.T1
SELECT 'A','序号1' UNION ALL
SELECT 'B','序号2' UNION ALL
SELECT 'C','序号3' UNION ALL
SELECT 'D','序号4' UNION ALL
SELECT 'E','序号5'
GO
create table dbo.T2
(
ID INT IDENTITY(1,1) NOT NULL
,A NVARCHAR(10) NULL
,B NVARCHAR(10) NULL
,C NVARCHAR(10) NULL
,D NVARCHAR(10) NULL
,E NVARCHAR(10) NULL
,CONSTRAINT PK_T2 PRIMARY KEY (ID ASC)
)
INSERT INTO dbo.T2
SELECT '值1','值2', '值3', '值4', '值5'
GO
SELECT A.ENFIELD,A.CHNAME,B.VALU
FROM dbo.T1 AS A
INNER JOIN (
SELECT Turn,VALU
FROM
(
SELECT A,B,C,D,E FROM dbo.T2
) AS P
UNPIVOT
(
VALU FOR Turn IN (A,B,C,D,E)
)AS Temp) AS B
ON A.ENFIELD=B.Turn
你这个是2005的吧?我的数据库是2000的。 :(
if object_id('表1')is not null
drop table 表1
if object_id('表2') is not null
drop table 表2
if object_id('c') is not null
drop table c
gocreate table 表1
( ENFIELD nvarchar(2),
CHNAME nvarchar(6)
)
insert into 表1 select 'A','序号1'
union all select 'B','序号2'
union all select 'C','序号3'
union all select 'D','序号4'
union all select 'E','序号5'
go
create table 表2
( A nvarchar(4),
B nvarchar(4),
C nvarchar(4),
D nvarchar(4),
E nvarchar(4)
)
insert into 表2 select '值1' ,'值2', '值3', '值4', '值5'
goselect A AS VALUSE,ENFIELD INTO c FROM
(select A ,'A' AS ENFIELD from 表2
union all
select B ,'B' from 表2
union all
select C ,'C' from 表2
union all
select D,'D' from 表2
union all
select E ,'E'from 表2) bselect a.ENFIELD,a.CHNAME,c.VALUSE FROM 表1 a inner join c on a.ENFIELD=c.ENFIELD
------
A 序号1 值1
B 序号2 值2
C 序号3 值3
D 序号4 值4
E 序号5 值5
set @s=';with t as (select *, (select case ENFIELD'
select @s=@s + ' when '''+ENFIELD+''' then '+ENFIELD from t1 set @s=@s+' end from t2) [values] from t1)'+
' select * from t where (ENFIELD=''A'' and [VALUES]=''值1'') or (ENFIELD=''C'' and [VALUES]=''值3'')' exec(@s) -----------------运行提示信息: ';' 附近有语法错误。请问,在SQL2000下,应该如何拼写动态SQL?
if object_id('t1') is not null
drop table t1
go
create table t1(ENFIELD char(1), CHNAME varchar(10))
insert into t1
select 'A', '序号1' union all
select 'B', '序号2' union all
select 'C', '序号3' union all
select 'D', '序号4' union all
select 'E', '序号5'if object_id('t2') is not null
drop table t2
go
create table t2(A varchar(10), B varchar(10), C varchar(10), D varchar(10), E varchar(10))
insert into t2
select '值1', '值2', '值3', '值4', '值5' DECLARE @sql VARCHAR(8000)
SELECT @sql=ISNULL(@sql + ' UNION ALL ','') +
'SELECT ENFIELD=''' + name + ''',[VALUES]=(SELECT TOP 1 ' + name + ' FROM t2)'
FROM syscolumns
WHERE id=object_id('t2')
print @sql
EXEC('SELECT a.ENFIELD ,a.CHNAME,b.[VALUES] FROM t1 a'+
' INNER JOIN (' + @sql + ') b ON a.ENFIELD=b.ENFIELD'+
' where (a.ENFIELD=''A'' and b.[VALUES]=''值'') or (a.ENFIELD=''C'' and b.[VALUES]=''值'')')
2.不使用存储过程或函数,这样就能同时适应于SQLSERVER和Oracle的需求,方便系统移植。缺点是可能会造成速度\效率降低一些。(我在JAVA中都append,实际运行效果还行吧。^_^)
我所拼写的SQL就是用的楼上各位提供的方法,可以通用于SQLSERVER和Oracle。最终拼写完成后的SQL大致的样子如下:Select ENFIELD,CHNAME,VALUE From t1 a INNER JOIN
(
Select 'A' as ID,(select RTrim(A) from t2 ) as VALUE FROM t2 --此处可以增加where条件
union all
Select 'B' as ID,(select RTrim(B) from t2 ) as VALUE FROM t2
union all
Select 'C' as ID,(select RTrim(C) from t2 ) as VALUE FROM t2
--如果有,继续拼接
......
) b
on a.ENFIELD=b.ID
and ((ENFIELD='A'and VALUE='值1') or (ENFIELD='C'and VALUE= '值3')) --过滤条件。
---------再次表示感谢。尤其对npkaida 和 fcuandy 。 :)