经典短小实用的SQL语句

来源:互联网 发布:php 文件上传方法 编辑:程序博客网 时间:2024/05/01 20:52

1. 固定列数的行列转换

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;

 

2. --SQL2005

CREATE TABLE #t (id int IDENTITY(1,1) PRIMARY KEY,nums int)
GO

INSERT INTO #t
SELECT abs(CHECKSUM(NEWID())%100000)
GO 10000   ----生成10000笔资料,可以是任意一数字

SELECT * FROM #t
GO
DROP TABLE #t
GO

3. --日期转换参数,值得收藏
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

 

4. 说明:普通行列转换(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


5.  --按某一字段分组取最大(小)值所在行的数据
数据如下:
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 行受影响)
*/

 

 

 


6. 合并列值

表结构,数据如下:
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

 

7. 分拆列值

有表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 行受影响)
*/

 

 

8. 标题:分解字符串并查询相关数据

问题:通过分解一个带某种符号分隔的字符串在数据库中查找相关数据。
例如 @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 行)
*/


9.  --返程问题,找出雇员从本地出发后直接返回的情况
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 行受影响)
*/

10. --库存先进先出简单例子:

create table t(
id
int identity(1,1),
name
varchar(50),--商品名称
j int,        --入库数量
c int,        --出库数量
jdate datetime --入库时间
)
insert into t(name,j,c,jdate) select  'A',100,0,'2007-12-01'
insert into t(name,j,c,jdate) select  'A',200,0,'2008-01-07'
insert into t(name,j,c,jdate) select  'B',320,0,'2007-12-21'
insert into t(name,j,c,jdate) select  'A',100,0,'2008-01-15'
insert into t(name,j,c,jdate) select  'B',90,0,'2008-02-03'
insert into t(name,j,c,jdate) select  'A',460,0,'2008-02-01'
insert into t(name,j,c,jdate) select  'A',510,0,'2008-03-01'
go



create proc wsp
@name varchar(50),--商品名称
@cost int         --销售量
as
--先得出该货物的库存是否够
declare @spare float --剩余库存
select @spare=sum(j)-sum(c) from t where name=@name
if(@spare>=@cost)
begin
   
--根据入库日期采用先进先出原则对货物的库存进行处理
    update t set c=
   
case when (select @cost-isnull(sum(j),0)+isnull(sum(c),0) from t where name=@name and jdate<=a.jdate and j!=c)>=0
   
then a.j
   
else
       
case when (select @cost-isnull(sum(j),0)+isnull(sum(c),0) from t where name=@name and jdate<a.jdate and j!=c)<0 then 0
       
else (select @cost-isnull(sum(j),0)+isnull(sum(c),0)+a.c from t where name=@name and jdate<a.jdate and j!=c)
       
end
   
end
   
from t a where name=@name and j!=c
end
else
   
raiserror('库存不足',16,1)   
   
return
go


--测试:

exec wsp @name='A',@cost=180
select * from t


--drop table t
--
drop proc wsp

 

11. --bom结构,查找节点下所有子节点:

create table os(id int,parentid int,desn varchar(10))
insert into os select 1,0,'体育用品'
insert into os select 2,0,'户外运动'
insert into os select 3,1,'篮球'
insert into os select 4,1,'足球'
insert into os select 5,2,'帐篷'
insert into os select 6,2,'登山鞋'
insert into os select 7,0,'男士用品'
insert into os select 8,7,'刮胡刀'
insert into os select 9,3,'大号篮球'

--求个节点下所有子节点:
create function f_cid(@id int)
returns varchar(500)
as
begin
    
declare @t table(id int,parentid int,desn varchar(10),lev int)
    
declare @lev int
    
set @lev=1
    
insert into @t select *,@lev from  os where id=@id
    
while(@@rowcount>0)
    
begin
         
set @lev=@lev+1
         
insert into @t select a.*,@lev from os a,@t b
         
where a.parentid=b.id and b.lev=@lev-1
    
end
    
declare @cids varchar(500)
    
select @cids=isnull(@cids+',','')+ltrim(id) from @t order by lev
    
return @cids
end
go

--调用函数
select *,ids=dbo.f_cid(id) from os


--得到每个节点路径:
create proc wsp2
@id int
as
select *,cast(' ' as varchar(10)) fullpath  into #os from os
DECLARE @i int,@j int
set @i=0
set @j=1
select @i=max(parentid) from #os
update #os set fullpath=id
while @j<=@i
begin
      
update #os set fullpath=a.fullpath+','+ltrim(#os.id)
           
from #os inner join #os a on #os.parentid=a.id
      
where #os.parentid=@j
      
set @j=@j+1
end
select * from #os
go
--调用存储过程
exec wsp2 1

 

12. set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go


ALTER trigger [tri_updatesalary_Mem_Type]
on [dbo].[SalaryIncrease]
after 
insert
as
declare @i int
set @i=@@identity

update m
set m.Mem_Type=case when s.SMark>500000 then '退休会员'--500000
                   when s.SMark>400000 then '钻石五级'--400000
                   when s.SMark>300000 then '钻石四级'--300000
                   when s.SMark>200000 then '钻石三级'--200000
                   when s.SMark>100000 then '钻石二级'--100000
                   when s.SMark>50000 then '钻石一级'--50000
                   when s.SMark>40000 then '五星级'--40000
                   when s.SMark>30000 then '四星级'--30000
                   when s.SMark>20000 then '三星级'--20000
                   when s.SMark>10000 then '二星级'--10000
                   when s.SMark>5000 then '一星级'--5000
                   else '一般VIP会员'
              
end
from MemberInfo m
 
join (select s.SCardName,sum(s.SMark) as SMark
         
from SalaryIncrease s join inserted i on s.SCardName=i.SCardName group by s.SCardName) s
   
on m.Mem_Num=s.SCardName

--if exists(select * from MemberInfo m join inserted i on m.Mem_Num=i.SCardName and m.Mem_Mark>100 )
if exists (select  m.SCardName,sum(m.ShopMark)as mark from(select m.SCardName,m.ShopMark  from ShoppingMark m join inserted i on m.SCardName=i.SCardName
where year(m.SDate)=year(getdate()) and month(m.SDate)=month(getdate())) m
group by m.SCardName  having sum(m.ShopMark)>100)
/**/
/* --最新的(我写的,上面是整合魅影的)select * from ShoppingMark SM join (select m.SCardName,sum(m.ShopMark) as Mark from ShoppingMark m join inserted i on m.SCardName=i.SCardName group by m.SCardName) s
on SM.SCardName=s.ScardName where month(SDate)=month(getdate()) and year(SDate)=year(getdate()) and s.Mark>100
*/
begin
update s
  
set s.SIncease=case
                     
--积分大于1000就是星级.所以不用判断是否是星级
                   when m.Mem_Type<>'一般VIP会员' then s.SMark*0.3
                  
else case
                         
when s.SMark>4000 then
                               s.SMark
*0.3
                       
--  when s.SMark>4000 then
                             --  200*0.2+200*0.23+200*0.25+200*0.28+(s.SMark-800)*0.3
                          when s.SMark>3000 then
                              
1000*0.2+1000*0.23+1000*0.25+(s.SMark-600)*0.28
                         
when s.SMark>2000 then
                              
1000*0.2+100*0.23+(s.SMark-400)*0.25 
                         
when s.SMark>1000 then
                               (s.SMark
-200)*.023+1000*0.2
                         
else  s.SMark*0.2
                      
end
                 
end
from SalaryIncrease as s
join inserted i
   
on s.SCardName=i.SCardName
 
join MemberInfo m
   
on (i.SCardName=m.Mem_Num and s.SID=@i) or (i.SCardName=m.Mem_Num and s.SIncease=0)
   
end
--go

13. create table tb(id varchar(3) , pid varchar(3) , name varchar(10))
insert into tb values('001' , null  , '广东省')
insert into tb values('002' , '001' , '广州市')
insert into tb values('003' , '001' , '深圳市')
insert into tb values('004' , '002' , '天河区')
insert into tb values('005' , '003' , '罗湖区')
insert into tb values('006' , '003' , '福田区')
insert into tb values('007' , '003' , '宝安区')
insert into tb values('008' , '007' , '西乡镇')
insert into tb values('009' , '007' , '龙华镇')
insert into tb values('010' , '007' , '松岗镇')
go

--查询指定节点及其所有子节点的函数
create function f_cid(@ID varchar(3)) returns @t_level table(id varchar(3) , level int)
as
begin
 
declare @level int
 
set @level = 1
 
insert into @t_level select @id , @level
 
while @@ROWCOUNT > 0
 
begin
   
set @level = @level + 1
   
insert into @t_level select a.id , @level
   
from tb a , @t_Level b
   
where a.pid = b.id and b.level = @level - 1
 
end
 
return
end
go

--调用函数查询001(广东省)及其所有子节点
select a.* from tb a , f_cid('001') b where a.id = b.id order by a.id
/*
id  pid  name     
---- ---- ----------
001  NULL 广东省
002  001  广州市
003  001  深圳市
004  002  天河区
005  003  罗湖区
006  003  福田区
007  003  宝安区
008  007  西乡镇
009  007  龙华镇
010  007  松岗镇

(所影响的行数为 10 行)
*/

--调用函数查询002(广州市)及其所有子节点
select a.* from tb a , f_cid('002') b where a.id = b.id order by a.id
/*
id  pid  name     
---- ---- ----------
002  001  广州市
004  002  天河区

(所影响的行数为 2 行)
*/

--调用函数查询003(深圳市)及其所有子节点
select a.* from tb a , f_cid('003') b where a.id = b.id order by a.id
/*
id  pid  name     
---- ---- ----------
003  001  深圳市
005  003  罗湖区
006  003  福田区
007  003  宝安区
008  007  西乡镇
009  007  龙华镇
010  007  松岗镇

(所影响的行数为 7 行)
*/

drop table tb
drop function f_cid

 

 

 

14.  说明:以日期或月份分表进行多日、多月查询连表查询的有关写法
*/


Create Procedure  Search
@date1 datetime, --起始时间
@date2 datetime  --终止时间
as
declare @date1New datetime
@rq varchar(6),
@i int , --记录循环次数
@s varchar(5000) --根据表多少 可以扩大它
set @rq=convert(varchar,@date1,12) --把时间格式化 比如2008-06-20 变成了080620


set @s='select * from sensor'+@rq --初始化 @s='select * from sensor080620' 这样第一个表就有了

set @i=datediff(d,@date1,@date2) --日期相减

while @i>0
begin
--如果是非常重要的系统可以在这里加上该物理表是否存在的语句
--
if   exists(select   *   from   dbo.sysobjects   where  
--
id   =   object_id(N'c')   and   OBJECTPROPERTY(id,N'IsUserTable')=1)
--
begin    
--
SELECT '存在 ' 
--
end
  
set @date1New= dateadd(day,@i,@date1)
set @rq=convert(varchar,@date1New,12)
--如果是按月进行查询 就修改上面
set @s= @s+' union all select * from sensor'+@rq
set @i=@i-1 --累加
end

select @s
--exec(@S)
go


exec Search '2008-06-20 00:11:11.000','2008-07-25 00:11:11.000'
 
drop Procedure  Search


15.  /*08.09.20*/

select * from employee

use master /*显示表结构*/
exec sp_helpdb
GO

use pubs
exec sp_help
GO

use pubs
exec sp_help employee
GO

select lname,job_lvl
from employee
where job_lvl<=50

select lname,job_lvl/*使用BETWEEN条件*/
from employee
where job_lvl BETWEEN 100 AND 200

select lname,job_id,job_lvl/*使用IN成员条件测试在列表中的值*/
from employee
where job_lvl IN (100,170,200)

select emp_id,lname,job_id,job_lvl/*使用NOT操作*/
from employee
where job_lvl NOT IN(100,170,200)

select title_id,title,type,price
from titles
where price IS NULL

select lname,job_lvl,job_lvl/*优先规则AND在前*/
from employee
where job_lvl=5
OR job_lvl=7
AND job_lvl>160

select lname,job_lvl,job_lvl/*用圆括号强制优先权*/
from employee
where (job_lvl=5
OR job_lvl=7)
AND job_lvl>160

select lname,job_id,job_lvl,hire_date/*用ORDER BY子句进行排序(升序排列)*/
from employee
ORDER BY hire_date

select lname,job_id,job_lvl,hire_date/*用DESC降序排列*/
from employee
ORDER BY hire_date DESC

select emp_id,lname,job_lvl*2 "Double job_lvl"/*用列别名排序*/
from employee
ORDER BY "Double job_lvl"

select lname,job_id,job_lvl/*多列排序*/
from employee
ORDER BY job_id,job_lvl DESC

/*
小结下:主要掌握WHERE子句限制输出行
    使用比较条件
    使用BETWEEN,IN,AND,NOT,OR操作
  最后掌握使用ORDER BY子句排序输出行
        所有操作在数据库pubs里进行
*/

 

原创粉丝点击