固定列数的行列转换
如
student subject grade
--------- ---------- --------
student1 语文 80
student1 数学 70
student1 英语 60
student2 语文 90
student2 数学 80
student2 英语 100
……
转换为
语文 数学 英语
student1 80 70 60
student2 90 80 100
……
语句如下:select student,
sum(decode(subject,'语文', grade,null)) "语文",
sum(decode(subject,'数学', grade,null)) "数学",
sum(decode(subject,'英语', grade,null)) "英语"
from table
group by student;
--日期转换参数,值得收藏
select
CONVERT(varchar,
getdate(),
120 )
2004-09-12
11:06:08
select
replace(replace(replace(CONVERT(varchar,
getdate(),
120 ),'-',''),'
',''),':','')
20040912110608
select
CONVERT(varchar(12) ,
getdate(),
111 )
2004/09/12
select
CONVERT(varchar(12) ,
getdate(),
112 )
20040912
select
CONVERT(varchar(12) ,
getdate(),
102 )
2004.09.12
其它我不常用的日期格式转换方法:
select
CONVERT(varchar(12) ,
getdate(),
101 )
09/12/2004
select
CONVERT(varchar(12) ,
getdate(),
103 )
12/09/2004
select
CONVERT(varchar(12) ,
getdate(),
104 )
12.09.2004
select
CONVERT(varchar(12) ,
getdate(),
105 )
12-09-2004
select
CONVERT(varchar(12) ,
getdate(),
106 )
12
09
2004
select
CONVERT(varchar(12) ,
getdate(),
107 )
09
12,
2004
select
CONVERT(varchar(12) ,
getdate(),
108 )
11:06:08
select
CONVERT(varchar(12) ,
getdate(),
109 )
09
12
2004
1
select
CONVERT(varchar(12) ,
getdate(),
110 )
09-12-2004
select
CONVERT(varchar(12) ,
getdate(),
113 )
12
09
2004
1
select
CONVERT(varchar(12) ,
getdate(),
114 )
11:06:08.177
/*
标题:普通行列转换(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
end
drop
table tb
--按某一字段分组取最大(小)值所在行的数据
--(爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 2007-10-23于浙江杭州)
/*
数据如下:
name val memo
a 2 a2(a的第二个值)
a 1 a1--a的第一个值
a 3 a3:a的第三个值
b 1 b1--b的第一个值
b 3 b3:b的第三个值
b 2 b2b2b2b2
b 4 b4b4
b 5 b5b5b5b5b5
*/
--创建表并插入数据:
create
table tb(name
varchar(10),val
int,memo
varchar(20))
insert
into tb values('a',
2,
'a2(a的第二个值)')
insert
into tb values('a',
1,
'a1--a的第一个值')
insert
into tb values('a',
3,
'a3:a的第三个值')
insert
into tb values('b',
1,
'b1--b的第一个值')
insert
into tb values('b',
3,
'b3:b的第三个值')
insert
into tb values('b',
2,
'b2b2b2b2')
insert
into tb values('b',
4,
'b4b4')
insert
into tb values('b',
5,
'b5b5b5b5b5')
go
--一、按name分组取val最大的值所在行的数据。
--方法1:
select a.*
from tb a
where val = (select
max(val)
from tb where name
= a.name)
order by a.name
--方法2:
select a.*
from tb a
where not
exists(select
1
from tb
where name
= a.name and val
> a.val)
--方法3:
select a.*
from tb a,(select name,max(val) val
from tb
group by name) b
where a.name
= b.name
and a.val = b.val
order
by a.name
--方法4:
select a.*
from tb a
inner join (select name ,
max(val) val
from tb
group by name) b
on a.name
= b.name and a.val
= b.val
order by a.name
--方法5
select a.*
from tb a
where 1
> (select
count(*)
from tb
where name
= a.name and val
> a.val )
order by a.name
/*
name val memo
---------- ----------- --------------------
a 3 a3:a的第三个值
b 5 b5b5b5b5b5
*/
--二、按name分组取val最小的值所在行的数据。
--方法1:
select a.*
from tb a
where val = (select
min(val)
from tb where name
= a.name)
order by a.name
--方法2:
select a.*
from tb a
where not
exists(select
1
from tb
where name
= a.name and val
< a.val)
--方法3:
select a.*
from tb a,(select name,min(val) val
from tb
group by name) b
where a.name
= b.name
and a.val = b.val
order
by a.name
--方法4:
select a.*
from tb a
inner join (select name ,
min(val) val
from tb
group by name) b
on a.name
= b.name and a.val
= b.val
order by a.name
--方法5
select a.*
from tb a
where 1
> (select
count(*)
from tb
where name
= a.name and val
< a.val)
order by a.name
/*
name val memo
---------- ----------- --------------------
a 1 a1--a的第一个值
b 1 b1--b的第一个值
*/
--三、按name分组取第一次出现的行所在的数据。
select a.*
from tb a
where val = (select
top
1 val
from tb
where name
= a.name) order
by a.name
/*
name val memo
---------- ----------- --------------------
a 2 a2(a的第二个值)
b 1 b1--b的第一个值
*/
--四、按name分组随机取一条数据。
select a.*
from tb a
where val = (select
top
1 val
from tb
where name
= a.name order
by newid())
order
by a.name
/*
name val memo
---------- ----------- --------------------
a 1 a1--a的第一个值
b 5 b5b5b5b5b5
*/
--五、按name分组取最小的两个(N个)val
select a.*
from tb a
where 2
> (select
count(*)
from tb
where name
= a.name and val
< a.val )
order by a.name,a.val
select a.*
from tb a
where val in (select
top
2 val
from tb
where name=a.name
order
by val) order
by a.name,a.val
select a.*
from tb a
where exists (select
count(*)
from tb
where name
= a.name and val
< a.val
having Count(*)
< 2)
order
by a.name
/*
name val memo
---------- ----------- --------------------
a 1 a1--a的第一个值
a 2 a2(a的第二个值)
b 1 b1--b的第一个值
b 2 b2b2b2b2
*/
--六、按name分组取最大的两个(N个)val
select a.*
from tb a
where 2
> (select
count(*)
from tb
where name
= a.name and val
> a.val )
order by a.name,a.val
select a.*
from tb a
where val in (select
top
2 val
from tb
where name=a.name
order
by val desc)
order
by a.name,a.val
select a.*
from tb a
where exists (select
count(*)
from tb
where name
= a.name and val
> a.val
having Count(*)
< 2)
order
by a.name
/*
name val memo
---------- ----------- --------------------
a 2 a2(a的第二个值)
a 3 a3:a的第三个值
b 4 b4b4
b 5 b5b5b5b5b5
*/
--七,如果整行数据有重复,所有的列都相同。
/*
数据如下:
name val memo
a 2 a2(a的第二个值)
a 1 a1--a的第一个值
a 1 a1--a的第一个值
a 3 a3:a的第三个值
a 3 a3:a的第三个值
b 1 b1--b的第一个值
b 3 b3:b的第三个值
b 2 b2b2b2b2
b 4 b4b4
b 5 b5b5b5b5b5
*/
--在sql server 2000中只能用一个临时表来解决,生成一个自增列,先对val取最大或最小,然后再通过自增列来取数据。
--创建表并插入数据:
create
table tb(name
varchar(10),val
int,memo
varchar(20))
insert
into tb values('a',
2,
'a2(a的第二个值)')
insert
into tb values('a',
1,
'a1--a的第一个值')
insert
into tb values('a',
1,
'a1--a的第一个值')
insert
into tb values('a',
3,
'a3:a的第三个值')
insert
into tb values('a',
3,
'a3:a的第三个值')
insert
into tb values('b',
1,
'b1--b的第一个值')
insert
into tb values('b',
3,
'b3:b的第三个值')
insert
into tb values('b',
2,
'b2b2b2b2')
insert
into tb values('b',
4,
'b4b4')
insert
into tb values('b',
5,
'b5b5b5b5b5')
go
select
* , px =
identity(int,1,1)
into tmp
from tb
select m.name,m.val,m.memo
from
(
select t.*
from tmp t
where val = (select
min(val)
from tmp where name
= t.name)
) m where px
= (select
min(px)
from
(
select t.*
from tmp t
where val = (select
min(val)
from tmp where name
= t.name)
) n where n.name
= m.name)
drop
table tb,tmp
/*
name val memo
---------- ----------- --------------------
a 1 a1--a的第一个值
b 1 b1--b的第一个值
(2 行受影响)
*/
--在sql server 2005中可以使用row_number函数,不需要使用临时表。
--创建表并插入数据:
create
table tb(name
varchar(10),val
int,memo
varchar(20))
insert
into tb values('a',
2,
'a2(a的第二个值)')
insert
into tb values('a',
1,
'a1--a的第一个值')
insert
into tb values('a',
1,
'a1--a的第一个值')
insert
into tb values('a',
3,
'a3:a的第三个值')
insert
into tb values('a',
3,
'a3:a的第三个值')
insert
into tb values('b',
1,
'b1--b的第一个值')
insert
into tb values('b',
3,
'b3:b的第三个值')
insert
into tb values('b',
2,
'b2b2b2b2')
insert
into tb values('b',
4,
'b4b4')
insert
into tb values('b',
5,
'b5b5b5b5b5')
go
select m.name,m.val,m.memo
from
(
select
* , px = row_number()
over(order
by name , val)
from tb
) m where px
= (select
min(px)
from
(
select
* , px = row_number()
over(order
by name , val)
from tb
) n where n.name
= m.name)
drop
table tb
/*
name val memo
---------- ----------- --------------------
a 1 a1--a的第一个值
b 1 b1--b的第一个值
(2 行受影响)
*/
合并列值
原著:邹建
改编:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 2007-12-16 广东深圳
表结构,数据如下:
id value
----- ------
1 aa
1 bb
2 aaa
2 bbb
2 ccc
需要得到结果:
id values
------ -----------
1 aa,bb
2 aaa,bbb,ccc
即:group by id, 求 value 的和(字符串相加)
1. 旧的解决方法(在sql server 2000中只能用函数解决。)
--1. 创建处理函数
create table tb(id int, value varchar(10))
insert into tb values(1, 'aa')
insert into tb values(1, 'bb')
insert into tb values(2, 'aaa')
insert into tb values(2, 'bbb')
insert into tb values(2, 'ccc')
go
CREATE FUNCTION dbo.f_str(@id int)
RETURNS varchar(8000)
AS
BEGIN
DECLARE @r varchar(8000)
SET @r = ''
SELECT @r = @r + ',' + value FROM tb WHERE id=@id
RETURN STUFF(@r, 1, 1, '')
END
GO
-- 调用函数
SELECt id, value = dbo.f_str(id) FROM tb GROUP BY id
drop table tb
drop function dbo.f_str
/*
id value
----------- -----------
1 aa,bb
2 aaa,bbb,ccc
(所影响的行数为 2 行)
*/
--2、另外一种函数.
create table tb(id int, value varchar(10))
insert into tb values(1, 'aa')
insert into tb values(1, 'bb')
insert into tb values(2, 'aaa')
insert into tb values(2, 'bbb')
insert into tb values(2, 'ccc')
go
--创建一个合并的函数
create function f_hb(@id int)
returns varchar(8000)
as
begin
declare @str varchar(8000)
set @str = ''
select @str = @str + ',' + cast(value as varchar) from tb where id = @id
set @str = right(@str , len(@str) - 1)
return(@str)
End
go
--调用自定义函数得到结果:
select distinct id ,dbo.f_hb(id) as value from tb
drop table tb
drop function dbo.f_hb
/*
id value
----------- -----------
1 aa,bb
2 aaa,bbb,ccc
(所影响的行数为 2 行)
*/
2. 新的解决方法(在sql server 2005中用OUTER APPLY等解决。)
create table tb(id int, value varchar(10))
insert into tb values(1, 'aa')
insert into tb values(1, 'bb')
insert into tb values(2, 'aaa')
insert into tb values(2, 'bbb')
insert into tb values(2, 'ccc')
go
-- 查询处理
SELECT * FROM(SELECT DISTINCT id FROM tb)A OUTER APPLY(
SELECT [values]= STUFF(REPLACE(REPLACE(
(
SELECT value FROM tb N
WHERE id = A.id
FOR XML AUTO
), ' <N value="', ','), '"/>', ''), 1, 1, '')
)N
drop table tb
/*
id values
----------- -----------
1 aa,bb
2 aaa,bbb,ccc
(2 行受影响)
*/
--SQL2005中的方法2
create table tb(id int, value varchar(10))
insert into tb values(1, 'aa')
insert into tb values(1, 'bb')
insert into tb values(2, 'aaa')
insert into tb values(2, 'bbb')
insert into tb values(2, 'ccc')
go
select id, [values]=stuff((select ','+[value] from tb t where id=tb.id for xml path('')), 1, 1, '')
from tb
group by id
/*
id values
----------- --------------------
1 aa,bb
2 aaa,bbb,ccc
(2 row(s) affected)
*/
drop table tb
分拆列值
原著:邹建
改编:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 2007-12-16 广东深圳
有表tb, 如下:
id value
----------- -----------
1 aa,bb
2 aaa,bbb,ccc
欲按id,分拆value列, 分拆后结果如下:
id value
----------- --------
1 aa
1 bb
2 aaa
2 bbb
2 ccc
1. 旧的解决方法(sql server 2000)
SELECT TOP 8000 id = IDENTITY(int, 1, 1) INTO # FROM syscolumns a, syscolumns b
SELECT A.id, SUBSTRING(A.[values], B.id, CHARINDEX(',', A.[values] + ',', B.id) - B.id)
FROM tb A, # B
WHERE SUBSTRING(',' + A.[values], B.id, 1) = ','
DROP TABLE #
2. 新的解决方法(sql server 2005)
create table tb(id int,value varchar(30))
insert into tb values(1,'aa,bb')
insert into tb values(2,'aaa,bbb,ccc')
go
SELECT A.id, B.value
FROM(
SELECT id, [value] = CONVERT(xml,' <root> <v>' + REPLACE([value], ',', ' </v> <v>') + ' </v> </root>') FROM tb
)A
OUTER APPLY(
SELECT value = N.v.value('.', 'varchar(100)') FROM A.[value].nodes('/root/v') N(v)
)B
DROP TABLE tb
/*
id value
----------- ------------------------------
1 aa
1 bb
2 aaa
2 bbb
2 ccc
(5 行受影响)
*/
/*
标题:分解字符串并查询相关数据
作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开)
时间:2008-03-18
地点:广东深圳
说明:通过使用函数等方法分解字符串查询相关数据。
问题:通过分解一个带某种符号分隔的字符串在数据库中查找相关数据。
例如 @str = '1,2,3',查询下表得到记录1,4,5,6
ID TypeID
1 1,2,3,4,5,6,7,8,9,10,11,12
2 2,3
3 3,7,8,9
4 2,6
5 4,5
6 6,7
*/
-----------------------------
create
table tb (ID
int , TypeID
varchar(30))
insert
into tb values(1 ,
'1,2,3,4,5,6,7,8,9,10,11,12')
insert
into tb values(2 ,
'2,3')
insert
into tb values(3 ,
'3,7,8,9')
insert
into tb values(4 ,
'2,6')
insert
into tb values(5 ,
'4,5')
insert
into tb values(6 ,
'6,7')
go
-----------------------------
--如果仅仅是一个,如@str = '1'.
declare
@str as
varchar(30)
set
@str =
'1'
select
* from tb
where
charindex(','
+ @str
+ ',' ,
','
+ TypeID
+ ',')
> 0
select
* from tb
where
','
+ TypeID
+ ','
like
'%,'
+ @str
+ ',%'
/*
ID TypeID
----------- ------------------------------
1 1,2,3,4,5,6,7,8,9,10,11,12
(所影响的行数为 1 行)
*/
-----------------------------
--如果包含两个,如@str = '1,2'.
declare
@str as
varchar(30)
set
@str =
'1,2'
select
* from tb
where
charindex(','
+ left(@str ,
charindex(',' ,
@str)
- 1)
+ ',' ,
','
+ typeid
+ ',')
> 0
or
charindex(','
+ substring(@str ,
charindex(',' ,
@str)
+ 1 ,
len(@str))
+ ',' ,
','
+ typeid
+ ',')
> 0
select
* from tb
where
','
+ typeid
+ ','
like
'%,'
+ left(@str ,
charindex(',' ,
@str)
- 1)
+ ',%'
or
','
+ typeid
+ ','
like
'%,'
+ substring(@str ,
charindex(',' ,
@str)
+ 1 ,
len(@str))
+ ',%'
/*
ID TypeID
----------- ------------------------------
1 1,2,3,4,5,6,7,8,9,10,11,12
2 2,3
4 2,6
(所影响的行数为 3 行)
*/
-------------------------------------------
--如果包含三个或四个,用PARSENAME函数来处理.
declare
@str as
varchar(30)
set
@str =
'1,2,3,4'
select
* from tb
where
charindex(','
+ parsename(replace(@str
, ',' ,
'.') ,
4)
+ ',' ,
','
+ typeid
+ ',')
> 0
or
charindex(','
+ parsename(replace(@str
, ',' ,
'.') ,
3)
+ ',' ,
','
+ typeid
+ ',')
> 0
or
charindex(','
+ parsename(replace(@str
, ',' ,
'.') ,
2)
+ ',' ,
','
+ typeid
+ ',')
> 0
or
charindex(','
+ parsename(replace(@str
, ',' ,
'.') ,
1)
+ ',' ,
','
+ typeid
+ ',')
> 0
select
* from tb
where
','
+ typeid
+ ','
like
'%,'
+ parsename(replace(@str
, ',' ,
'.') ,
4)
+ ',%'
or
','
+ typeid
+ ','
like
'%,'
+ parsename(replace(@str
, ',' ,
'.') ,
3)
+ ',%'
or
','
+ typeid
+ ','
like
'%,'
+ parsename(replace(@str
, ',' ,
'.') ,
2)
+ ',%'
or
','
+ typeid
+ ','
like
'%,'
+ parsename(replace(@str
, ',' ,
'.') ,
1)
+ ',%'
/*
ID TypeID
----------- ------------------------------
1 1,2,3,4,5,6,7,8,9,10,11,12
2 2,3
3 3,7,8,9
4 2,6
5 4,5
(所影响的行数为 5 行)
*/
---------------------------------------
--如果超过四个,则只能使用函数或动态SQL来分解并查询数据。
/*
名称:fn_split函数.
功能:实现字符串分隔功能的函数
*/
create
function dbo.fn_split(@inputstr
varchar(8000),
@seprator
varchar(10))
returns
@temp table (a
varchar(200))
as
begin
declare
@i int
set
@inputstr =
rtrim(ltrim(@inputstr))
set
@i =
charindex(@seprator ,
@inputstr)
while
@i >=
1
begin
insert
@temp values(left(@inputstr
, @i
- 1))
set
@inputstr =
substring(@inputstr ,
@i +
1 ,
len(@inputstr)
- @i)
set
@i =
charindex(@seprator ,
@inputstr)
end
if
@inputstr <>
'/'
insert
@temp values(@inputstr)
return
end
go
--调用
declare
@str as
varchar(30)
set
@str =
'1,2,3,4,5'
select
distinct m.*
from tb m,
(select
* from dbo.fn_split(@str,','))
n
where
charindex(','
+ n.a
+ ',' ,
','
+ m.typeid
+ ',')
> 0
drop
table tb
drop
function dbo.fn_split
/*
ID TypeID
----------- ------------------------------
1 1,2,3,4,5,6,7,8,9,10,11,12
2 2,3
3 3,7,8,9
4 2,6
5 4,5
(所影响的行数为 5 行)
*/
------------------------------------------
--使用动态SQL的语句。
declare
@str varchar(200)
declare
@sql as
varchar(1000)
set
@str =
'1,2,3,4,5'
set
@sql =
'select
''' +
replace(@str ,
',' ,
''' as id union all select
''')
set
@sql =
@sql
+ ''''
set
@sql =
'select distinct a.* from tb a , ('
+ @sql
+ ') b where charindex('
+ ''','' + b.id +
' +
''','''
+ ' ,
' +
''','' + a.typeid +
' +
''','''
+ ') > 0
'
exec (@sql)
/*
ID TypeID
----------- ------------------------------
1 1,2,3,4,5,6,7,8,9,10,11,12
2 2,3
3 3,7,8,9
4 2,6
5 4,5
(所影响的行数为 5 行)
*/
--返程问题,找出雇员从本地出发后直接返回的情况
create
table trav(name
nvarchar(10),date
datetime,comefrom
nvarchar(10),destin
nvarchar(10),id
int)
insert
into trav select
'张三','2007-01-01','上海','广州',1
insert
into trav select
'李四','2007-01-01','上海','广州',2
insert
into trav select
'李四','2007-02-01','上海','成都',3
insert
into trav select
'张三','2007-01-15','广州','上海',4
insert
into trav select
'张三','2007-02-06','上海','广州',5
insert
into trav select
'张三','2007-02-18','广州','上海',6
go
select a.name,a.date,a.comefrom,a.destin,b.date,b.comefrom,b.destin
from trav a
inner
join trav b
on a.name=b.name
and a.comefrom=b.destin
and a.destin=b.comefrom
where a.id<b.id
and
not exists(select
1
from trav
where comefrom=b.comefrom
and date<b.date
and date>a.date)
go
drop
table trav
/*
name date comefrom destin date comefrom destin
---------- ----------------------- ---------- ---------- ----------------------- ---------- ----------
张三 2007-01-01 00:00:00.000 上海 广州 2007-01-15 00:00:00.000 广州 上海
张三 2007-02-06 00:00:00.000 上海 广州 2007-02-18 00:00:00.000 广州 上海
(2 行受影响)
*/