SQL大全

设置内存选项:

SQL code
   
   
-- 设置 min server memory 配置项 EXEC sp_configure N ' min server memory (MB) ' , 0 -- 设置 max server memory 配置项 EXEC sp_configure N ' max server memory (MB) ' , 256 -- 使更新生效 RECONFIGURE WITH OVERRIDE


使用文件及文件组.sql:

SQL code
   
   
/* --功能说明 下面的代码是在SQL Server 2000上创建名为 MyDB 的数据库 该数据库包括1个主要数据文件、3个用户定义的文件组和1个日志文件 ALTER DATABASE语句将用户定义文件组指定为默认文件组。 之后,通过指默认的文件组来创建表,并且将图像数据和索引放到指定的文件组中。 最后,将文件组中的指定数据文件删除 -- */ -- 切换到 master 数据库 USE master GO -- A. 创建数据库 MyDB CREATE DATABASE MyDB ON PRIMARY -- 主文件组和主要数据文件 ( NAME = ' MyDB_Primary ' , FILENAME = ' c:/MyDB_Prm.mdf ' ), FILEGROUP MyDB_FG1 -- 用户定义文件组1 ( NAME = ' MyDB_FG1_Dat1 ' , FILENAME = ' c:/MyDB_FG1_1.ndf ' ), -- 次要数据文件1 ( NAME = ' MyDB_FG1_Dat2 ' , FILENAME = ' d:/MyDB_FG1_2.ndf ' ), -- 次要数据文件2 FILEGROUP MyDB_FG2 -- 用户定义文件组2 ( NAME = ' MyDB_FG1_Dat ' , FILENAME = ' e:/MyDB_FG2.ndf ' ) -- 次要数据文件 LOG ON -- 日志文件 ( NAME = ' MyDB_log ' , FILENAME = ' d:/MyDB.ldf ' ) GO -- B. 修改默认数据文件组 ALTER DATABASE MyDB MODIFY FILEGROUP MyDB_FG1 DEFAULT GO -- 切换到新建的数据库 MyDB USE MyDB -- C. 在默认文件组MyDB_FG1创建表,并且指定图像数据保存在用户定义文件组MMyDB_FG2 CREATE TABLE MyTable ( cola int PRIMARY KEY , colb char ( 8 ) , colc image ) TEXTIMAGE_ON MyDB_FG2 -- 在用户定义文件组MyDB_FG2上创建索引 CREATE INDEX IX_MyTable ON MyTable(cola) ON MyDB_FG2 GO -- D. 将要删除数据文件MyDB_FG1_Dat1上的数据转移到其他数据文件中,并且清空数据文件MyDB_FG1_Dat1 DBCC SHRINKFILE(MyDB_FG1_Dat1,EMPTYFILE) -- 删除数据文件MyDB_FG1_Dat1 ALTER DATABASE MyDB REMOVE FILE MyDB_FG1_Dat1


调整tempdb数据库的文件属性.sql:

SQL code
   
   
-- A. 将tempdb数据库的主数据文件大小设置为10MB。 ALTER DATABASE tempdb MODIFY FILE ( name = tempdev, size = 100 MB) GO -- B. 将tempdb数据库的主数据文件移动到指定的磁盘分区上,并且为其添加一个数据文件。 -- 移动主数据文件 ALTER DATABASE tempdb MODIFY FILE ( NAME = ' tempdev ' , FILENAME = ' d:/tempdb.mdf ' ) -- 添加次要数据文件 ALTER DATABASE tempdb ADD FILE ( NAME = ' tempdata_1 ' , FILENAME = ' d:/tempdb_data_1.ndf ' )


日期概念理解中的一些测试.sql:

SQL code
   
   
-- A. 测试 datetime 精度问题 DECLARE @t TABLE (date char ( 21 )) INSERT @t SELECT ' 1900-1-1 00:00:00.000 ' INSERT @t SELECT ' 1900-1-1 00:00:00.001 ' INSERT @t SELECT ' 1900-1-1 00:00:00.009 ' INSERT @t SELECT ' 1900-1-1 00:00:00.002 ' INSERT @t SELECT ' 1900-1-1 00:00:00.003 ' INSERT @t SELECT ' 1900-1-1 00:00:00.004 ' INSERT @t SELECT ' 1900-1-1 00:00:00.005 ' INSERT @t SELECT ' 1900-1-1 00:00:00.006 ' INSERT @t SELECT ' 1900-1-1 00:00:00.007 ' INSERT @t SELECT ' 1900-1-1 00:00:00.008 ' SELECT date,转换后的日期 = CAST (date as datetime ) FROM @t /* --结果 date 转换后的日期 --------------------- -------------------------- 1900-1-1 00:00:00.000 1900-01-01 00:00:00.000 1900-1-1 00:00:00.001 1900-01-01 00:00:00.000 1900-1-1 00:00:00.009 1900-01-01 00:00:00.010 1900-1-1 00:00:00.002 1900-01-01 00:00:00.003 1900-1-1 00:00:00.003 1900-01-01 00:00:00.003 1900-1-1 00:00:00.004 1900-01-01 00:00:00.003 1900-1-1 00:00:00.005 1900-01-01 00:00:00.007 1900-1-1 00:00:00.006 1900-01-01 00:00:00.007 1900-1-1 00:00:00.007 1900-01-01 00:00:00.007 1900-1-1 00:00:00.008 1900-01-01 00:00:00.007 (所影响的行数为 10 行) -- */ GO -- B. 对于 datetime 类型的纯日期和时间的十六进制表示 DECLARE @dt datetime -- 单纯的日期 SET @dt = ' 1900-1-2 ' SELECT CAST ( @dt as binary ( 8 )) -- 结果: 0x0000000100000000 -- 单纯的时间 SET @dt = ' 00:00:01 ' SELECT CAST ( @dt as binary ( 8 )) -- 结果: 0x000000000000012C GO -- C. 对于 smalldatetime 类型的纯日期和时间的十六进制表示 DECLARE @dt smalldatetime -- 单纯的日期 SET @dt = ' 1900-1-2 ' SELECT CAST ( @dt as binary ( 4 )) -- 结果: 0x00010000 -- 单纯的时间 SET @dt = ' 00:10 ' SELECT CAST ( @dt as binary ( 4 )) -- 结果: 0x0000000A
 
 
CONVERT在日期转换中的使用示例.sql:
SQL code
    
    
-- 字符转换为日期时,Style的使用 -- 1. Style=101时,表示日期字符串为:mm/dd/yyyy格式 SELECT CONVERT ( datetime , ' 11/1/2003 ' , 101 ) -- 结果:2003-11-01 00:00:00.000 -- 2. Style=101时,表示日期字符串为:dd/mm/yyyy格式 SELECT CONVERT ( datetime , ' 11/1/2003 ' , 103 ) -- 结果:2003-01-11 00:00:00.000 /* == 日期转换为字符串 == */ DECLARE @dt datetime SET @dt = ' 2003-1-11 ' -- 1. Style=101时,表示将日期转换为:mm/dd/yyyy 格式 SELECT CONVERT ( varchar , @dt , 101 ) -- 结果:01/11/2003 -- 2. Style=103时,表示将日期转换为:dd/mm/yyyy 格式 SELECT CONVERT ( varchar , @dt , 103 ) -- 结果:11/01/2003 /* == 这是很多人经常犯的错误,对非日期型转换使用日期的style样式 == */ SELECT CONVERT ( varchar , ' 2003-1-11 ' , 101 ) -- 结果:2003-1-11

SET DATEFORMAT对日期处理的影响.sql
SQL code
    
    
-- 1. /* --说明 SET DATEFORMAT设置对使用CONVERT把字符型日期转换为日期的处理也具有影响 但不影响明确指定了style的CONVERT处理。 -- */ -- 示例 ,在下面的示例中,第一个CONVERT转换未指定style,转换的结果受SET DATAFORMAT的影响,第二个CONVERT转换指定了style,转换结果受style的影响。 -- 设置输入日期顺序为 日/月/年 SET DATEFORMAT DMY -- 不指定Style参数的CONVERT转换将受到SET DATEFORMAT的影响 SELECT CONVERT ( datetime , ' 2-1-2005 ' ) -- 结果: 2005-01-02 00:00:00.000 -- 指定Style参数的CONVERT转换不受SET DATEFORMAT的影响 SELECT CONVERT ( datetime , ' 2-1-2005 ' , 101 ) -- 结果: 2005-02-01 00:00:00.000 GO -- 2. /* --说明 如果输入的日期包含了世纪部分,则对日期进行解释处理时 年份的解释不受SET DATEFORMAT设置的影响。 -- */ -- 示例,在下面的代码中,同样的SET DATEFORMAT设置,输入日期的世纪部分与不输入日期的世纪部分,解释的日期结果不同。 DECLARE @dt datetime -- 设置SET DATEFORMAT为:月日年 SET DATEFORMAT MDY -- 输入的日期中指定世纪部分 SET @dt = ' 01-2002-03 ' SELECT @dt -- 结果: 2002-01-03 00:00:00.000 -- 输入的日期中不指定世纪部分 SET @dt = ' 01-02-03 ' SELECT @dt -- 结果: 2003-01-02 00:00:00.000 GO -- 3. /* --说明 如果输入的日期不包含日期分隔符,那么SQL Server在对日期进行解释时 将忽略SET DATEFORMAT的设置。 -- */ -- 示例,在下面的代码中,不包含日期分隔符的字符日期,在不同的SET DATEFORMAT设置下,其解释的结果是一样的。 DECLARE @dt datetime -- 设置SET DATEFORMAT为:月日年 SET DATEFORMAT MDY SET @dt = ' 010203 ' SELECT @dt -- 结果: 2001-02-03 00:00:00.000 -- 设置SET DATEFORMAT为:日月年 SET DATEFORMAT DMY SET @dt = ' 010203 ' SELECT @dt -- 结果: 2001-02-03 00:00:00.000 -- 输入的日期中包含日期分隔符 SET @dt = ' 01-02-03 ' SELECT @dt -- 结果: 2003-02-01 00:00:00.000

SET LANGUAGE对日期处理的影响示例.sql
SQL code
    
    
-- 以下示例演示了在不同的语言环境(SET LANGUAGE)下,DATENAME与CONVERT函数的不同结果。 USE master -- 设置会话的语言环境为: English SET LANGUAGE N ' English ' SELECT DATENAME ( Month , GETDATE ()) AS [ Month ] , DATENAME (Weekday, GETDATE ()) AS [ Weekday ] , CONVERT ( varchar , GETDATE (), 109 ) AS [ CONVERT ] /* --结果: Month Weekday CONVERT ------------- -------------- ------------------------------- March Tuesday Mar 15 2005 8:59PM -- */ -- 设置会话的语言环境为: 简体中文 SET LANGUAGE N ' 简体中文 ' SELECT DATENAME ( Month , GETDATE ()) AS [ Month ] , DATENAME (Weekday, GETDATE ()) AS [ Weekday ] , CONVERT ( varchar , GETDATE (), 109 ) AS [ CONVERT ] /* --结果 Month Weekday CONVERT ------------- --------------- ----------------------------------------- 05 星期四 05 19 2005 2:49:20:607PM -- */

日期格式化处理.sql
SQL code
    
    
DECLARE @dt datetime SET @dt = GETDATE () -- 1.短日期格式:yyyy-m-d SELECT REPLACE ( CONVERT ( varchar ( 10 ), @dt , 120 ),N ' -0 ' , ' - ' ) -- 2.长日期格式:yyyy年mm月dd日 -- A. 方法1 SELECT STUFF ( STUFF ( CONVERT ( char ( 8 ), @dt , 112 ), 5 , 0 ,N ' ' ), 8 , 0 ,N ' ' ) + N ' ' -- B. 方法2 SELECT DATENAME ( Year , @dt ) + N ' ' + DATENAME ( Month , @dt ) + N ' ' + DATENAME ( Day , @dt ) + N ' ' -- 3.长日期格式:yyyy年m月d日 SELECT DATENAME ( Year , @dt ) + N ' ' + CAST ( DATEPART ( Month , @dt ) AS varchar ) + N ' ' + DATENAME ( Day , @dt ) + N ' ' -- 4.完整日期+时间格式:yyyy-mm-dd hh:mi:ss:mmm SELECT CONVERT ( char ( 11 ), @dt , 120 ) + CONVERT ( char ( 12 ), @dt , 114 )

日期推算处理.sql
SQL code
    
    
DECLARE @dt datetime SET @dt = GETDATE () DECLARE @number int SET @number = 3 -- 1.指定日期该年的第一天或最后一天 -- A. 年的第一天 SELECT CONVERT ( char ( 5 ), @dt , 120 ) + ' 1-1 ' -- B. 年的最后一天 SELECT CONVERT ( char ( 5 ), @dt , 120 ) + ' 12-31 ' -- 2.指定日期所在季度的第一天或最后一天 -- A. 季度的第一天 SELECT CONVERT ( datetime , CONVERT ( char ( 8 ), DATEADD ( Month , DATEPART (Quarter, @dt ) * 3 - Month ( @dt ) - 2 , @dt ), 120 ) + ' 1 ' ) -- B. 季度的最后一天(CASE判断法) SELECT CONVERT ( datetime , CONVERT ( char ( 8 ), DATEADD ( Month , DATEPART (Quarter, @dt ) * 3 - Month ( @dt ), @dt ), 120 ) + CASE WHEN DATEPART (Quarter, @dt ) in ( 1 , 4 ) THEN ' 31 ' ELSE ' 30 ' END ) -- C. 季度的最后一天(直接推算法) SELECT DATEADD ( Day , - 1 , CONVERT ( char ( 8 ), DATEADD ( Month , 1 + DATEPART (Quarter, @dt ) * 3 - Month ( @dt ), @dt ), 120 ) + ' 1 ' ) -- 3.指定日期所在月份的第一天或最后一天 -- A. 月的第一天 SELECT CONVERT ( datetime , CONVERT ( char ( 8 ), @dt , 120 ) + ' 1 ' ) -- B. 月的最后一天 SELECT DATEADD ( Day , - 1 , CONVERT ( char ( 8 ), DATEADD ( Month , 1 , @dt ), 120 ) + ' 1 ' ) -- C. 月的最后一天(容易使用的错误方法) SELECT DATEADD ( Month , 1 , DATEADD ( Day , - DAY ( @dt ), @dt )) -- 4.指定日期所在周的任意一天 SELECT DATEADD ( Day , @number - DATEPART (Weekday, @dt ), @dt ) -- 5.指定日期所在周的任意星期几 -- A. 星期天做为一周的第1天 SELECT DATEADD ( Day , @number - ( DATEPART (Weekday, @dt ) + @@DATEFIRST - 1 ) % 7 , @dt ) -- B. 星期一做为一周的第1天 SELECT DATEADD ( Day , @number - ( DATEPART (Weekday, @dt ) + @@DATEFIRST - 2 ) % 7 - 1 , @dt )
特殊日期加减函数.sql 
SQL code
    
    
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_DateADD] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_DateADD ] GO /* --特殊日期加减函数 对于日期指定部分的加减,使用DATEADD函数就可以轻松实现。 在实际的处理中,还有一种比较另类的日期加减处理 就是在指定的日期中,加上(或者减去)多个日期部分 比如将2005年3月11日,加上1年3个月11天2小时。 对于这种日期的加减处理,DATEADD函数的力量就显得有点不够。 本函数实现这样格式的日期字符串加减处理: y-m-d h:m:s.m | -y-m-d h:m:s.m 说明: 要加减的日期字符输入方式与日期字符串相同。日期与时间部分用空格分隔 最前面一个字符如果是减号(-)的话,表示做减法处理,否则做加法处理。 如果日期字符只包含数字,则视为日期字符中,仅包含天的信息。 -- */ /* --调用示例 SELECT dbo.f_DateADD(GETDATE(),'11:10') -- */ CREATE FUNCTION dbo.f_DateADD( @Date datetime , @DateStr varchar ( 23 ) ) RETURNS datetime AS BEGIN DECLARE @bz int , @s varchar ( 12 ), @i int IF @DateStr IS NULL OR @Date IS NULL OR ( CHARINDEX ( ' . ' , @DateStr ) > 0 AND @DateStr NOT LIKE ' %[:]%[:]%.% ' ) RETURN ( NULL ) IF @DateStr = '' RETURN ( @Date ) SELECT @bz = CASE WHEN LEFT ( @DateStr , 1 ) = ' - ' THEN - 1 ELSE 1 END , @DateStr = CASE WHEN LEFT ( @Date , 1 ) = ' - ' THEN STUFF ( RTRIM ( LTRIM ( @DateStr )), 1 , 1 , '' ) ELSE RTRIM ( LTRIM ( @DateStr )) END IF CHARINDEX ( ' ' , @DateStr ) > 1 OR CHARINDEX ( ' - ' , @DateStr ) > 1 OR ( CHARINDEX ( ' . ' , @DateStr ) = 0 AND CHARINDEX ( ' : ' , @DateStr ) = 0 ) BEGIN SELECT @i = CHARINDEX ( ' ' , @DateStr + ' ' ) , @s = REVERSE ( LEFT ( @DateStr , @i - 1 )) + ' - ' , @DateStr = STUFF ( @DateStr , 1 , @i , '' ) , @i = 0 WHILE @s > '' and @i < 3 SELECT @Date = CASE @i WHEN 0 THEN DATEADD ( Day , @bz * REVERSE ( LEFT ( @s , CHARINDEX ( ' - ' , @s ) - 1 )), @Date ) WHEN 1 THEN DATEADD ( Month , @bz * REVERSE ( LEFT ( @s , CHARINDEX ( ' - ' , @s ) - 1 )), @Date ) WHEN 2 THEN DATEADD ( Year , @bz * REVERSE ( LEFT ( @s , CHARINDEX ( ' - ' , @s ) - 1 )), @Date ) END , @s = STUFF ( @s , 1 , CHARINDEX ( ' - ' , @s ), '' ), @i = @i + 1 END IF @DateStr > '' BEGIN IF CHARINDEX ( ' . ' , @DateStr ) > 0 SELECT @Date = DATEADD (Millisecond , @bz * STUFF ( @DateStr , 1 , CHARINDEX ( ' . ' , @DateStr ), '' ), @Date ), @DateStr =LEFT ( @DateStr , CHARINDEX ( ' . ' , @DateStr ) - 1 ) + ' : ' , @i = 0 ELSE SELECT @DateStr = @DateStr + ' : ' , @i = 0 WHILE @DateStr > '' and @i < 3 SELECT @Date = CASE @i WHEN 0 THEN DATEADD (Hour, @bz *LEFT ( @DateStr , CHARINDEX ( ' : ' , @DateStr ) - 1 ), @Date ) WHEN 1 THEN DATEADD (Minute, @bz *LEFT ( @DateStr , CHARINDEX ( ' : ' , @DateStr ) - 1 ), @Date ) WHEN 2 THEN DATEADD (Second, @bz *LEFT ( @DateStr , CHARINDEX ( ' : ' , @DateStr ) - 1 ), @Date ) END , @DateStr = STUFF ( @DateStr , 1 , CHARINDEX ( ' : ' , @DateStr ), '' ), @i = @i + 1 END RETURN ( @Date ) END GO

查询指定日期段内过生日的人员.sql
SQL code
    
    
-- 测试数据 DECLARE @t TABLE (ID int ,Name varchar ( 10 ),Birthday datetime ) INSERT @t SELECT 1 , ' aa ' , ' 1999-01-01 ' UNION ALL SELECT 2 , ' bb ' , ' 1996-02-29 ' UNION ALL SELECT 3 , ' bb ' , ' 1934-03-01 ' UNION ALL SELECT 4 , ' bb ' , ' 1966-04-01 ' UNION ALL SELECT 5 , ' bb ' , ' 1997-05-01 ' UNION ALL SELECT 6 , ' bb ' , ' 1922-11-21 ' UNION ALL SELECT 7 , ' bb ' , ' 1989-12-11 ' DECLARE @dt1 datetime , @dt2 datetime -- 查询 2003-12-05 至 2004-02-28 生日的记录 SELECT @dt1 = ' 2003-12-05 ' , @dt2 = ' 2004-02-28 ' SELECT * FROM @t WHERE DATEADD ( Year , DATEDIFF ( Year ,Birthday, @dt1 ),Birthday) BETWEEN @dt1 AND @dt2 OR DATEADD ( Year , DATEDIFF ( Year ,Birthday, @dt2 ),Birthday) BETWEEN @dt1 AND @dt2 /* --结果 ID Name Birthday ---------------- ---------------- -------------------------- 1 aa 1999-01-01 00:00:00.000 7 bb 1989-12-11 00:00:00.000 -- */ -- 查询 2003-12-05 至 2006-02-28 生日的记录 SET @dt2 = ' 2006-02-28 ' SELECT * FROM @t WHERE DATEADD ( Year , DATEDIFF ( Year ,Birthday, @dt1 ),Birthday) BETWEEN @dt1 AND @dt2 OR DATEADD ( Year , DATEDIFF ( Year ,Birthday, @dt2 ),Birthday) BETWEEN @dt1 AND @dt2 /* --查询结果 ID Name Birthday ---------------- ----------------- -------------------------- 1 aa 1999-01-01 00:00:00.000 2 bb 1996-02-29 00:00:00.000 7 bb 1989-12-11 00:00:00.000 -- */

生成日期列表的函数.sql
SQL code
    
    
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_getdate] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_getdate ] GO /* --生成日期列表 生成指定年份的工作日/休息日列表 --邹建 2003.12(引用请保留此信息)-- */ /* --调用示例 --查询 2003 年的工作日列表 SELECT * FROM dbo.f_getdate(2003,0) --查询 2003 年的休息日列表 SELECT * FROM dbo.f_getdate(2003,1) --查询 2003 年全部日期列表 SELECT * FROM dbo.f_getdate(2003,NULL) -- */ CREATE FUNCTION dbo.f_getdate( @year int , -- 要查询的年份 @bz bit -- @bz=0 查询工作日,@bz=1 查询休息日,@bz IS NULL 查询全部日期 ) RETURNS @re TABLE (id int identity ( 1 , 1 ),Date datetime ,Weekday nvarchar ( 3 )) AS BEGIN DECLARE @tb TABLE (ID int IDENTITY ( 0 , 1 ),Date datetime ) INSERT INTO @tb (Date) SELECT TOP 366 DATEADD ( Year , @YEAR - 1900 , ' 1900-1-1 ' ) FROM sysobjects a ,sysobjects b UPDATE @tb SET Date = DATEADD ( DAY ,id,Date) DELETE FROM @tb WHERE Date > DATEADD ( Year , @YEAR - 1900 , ' 1900-12-31 ' ) IF @bz = 0 INSERT INTO @re (Date,Weekday) SELECT Date, DATENAME (Weekday,Date) FROM @tb WHERE ( DATEPART (Weekday,Date) + @@DATEFIRST - 1 ) % 7 BETWEEN 1 AND 5 ELSE IF @bz = 1 INSERT INTO @re (Date,Weekday) SELECT Date, DATENAME (Weekday,Date) FROM @tb WHERE ( DATEPART (Weekday,Date) + @@DATEFIRST - 1 ) % 7 IN ( 0 , 6 ) ELSE INSERT INTO @re (Date,Weekday) SELECT Date, DATENAME (Weekday,Date) FROM @tb RETURN END GO /* ==================================================================== */ if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_getdate] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_getdate ] GO /* --生成列表 生成指定日期段的日期列表 --邹建 2005.03(引用请保留此信息)-- */ /* --调用示例 --查询工作日 SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',0) --查询休息日 SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',1) --查询全部日期 SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',NULL) -- */ CREATE FUNCTION dbo.f_getdate( @begin_date Datetime , -- 要查询的开始日期 @end_date Datetime , -- 要查询的结束日期 @bz bit -- @bz=0 查询工作日,@bz=1 查询休息日,@bz IS NULL 查询全部日期 ) RETURNS @re TABLE (id int identity ( 1 , 1 ),Date datetime ,Weekday nvarchar ( 3 )) AS BEGIN DECLARE @tb TABLE (ID int IDENTITY ( 0 , 1 ),a bit ) INSERT INTO @tb (a) SELECT TOP 366 0 FROM sysobjects a ,sysobjects b IF @bz = 0 WHILE @begin_date <= @end_date BEGIN INSERT INTO @re (Date,Weekday) SELECT Date, DATENAME (Weekday,Date) FROM ( SELECT Date = DATEADD ( Day ,ID, @begin_date ) FROM @tb )a WHERE Date <= @end_date AND ( DATEPART (Weekday,Date) + @@DATEFIRST - 1 ) % 7 BETWEEN 1 AND 5 SET @begin_date = DATEADD ( Day , 366 , @begin_date ) END ELSE IF @bz = 1 WHILE @begin_date <= @end_date BEGIN INSERT INTO @re (Date,Weekday) SELECT Date, DATENAME (Weekday,Date) FROM ( SELECT Date = DATEADD ( Day ,ID, @begin_date ) FROM @tb )a WHERE Date <= @end_date AND ( DATEPART (Weekday,Date) + @@DATEFIRST - 1 ) % 7 in ( 0 , 6 ) SET @begin_date = DATEADD ( Day , 366 , @begin_date ) END ELSE WHILE @begin_date <= @end_date BEGIN INSERT INTO @re (Date,Weekday) SELECT Date, DATENAME (Weekday,Date) FROM ( SELECT Date = DATEADD ( Day ,ID, @begin_date ) FROM @tb )a WHERE Date <= @end_date SET @begin_date = DATEADD ( Day , 366 , @begin_date ) END RETURN END GO
工作日处理函数(标准节假日).sql 
SQL code
      
      
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_WorkDay] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_WorkDay ] GO -- 计算两个日期相差的工作天数 CREATE FUNCTION f_WorkDay( @dt_begin datetime , -- 计算的开始日期 @dt_end datetime -- 计算的结束日期 ) RETURNS int AS BEGIN DECLARE @workday int , @i int , @bz bit , @dt datetime IF @dt_begin > @dt_end SELECT @bz = 1 , @dt = @dt_begin , @dt_begin = @dt_end , @dt_end = @dt ELSE SET @bz = 0 SELECT @i = DATEDIFF ( Day , @dt_begin , @dt_end ) + 1 , @workday = @i / 7 * 5 , @dt_begin = DATEADD ( Day , @i / 7 * 7 , @dt_begin ) WHILE @dt_begin <= @dt_end BEGIN SELECT @workday = CASE WHEN ( @@DATEFIRST + DATEPART (Weekday, @dt_begin ) - 1 ) % 7 BETWEEN 1 AND 5 THEN @workday + 1 ELSE @workday END , @dt_begin = @dt_begin + 1 END RETURN ( CASE WHEN @bz = 1 THEN - @workday ELSE @workday END ) END GO /* ================================================================= */ if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_WorkDayADD] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_WorkDayADD ] GO -- 在指定日期上,增加指定工作天数后的日期 CREATE FUNCTION f_WorkDayADD( @date datetime , -- 基础日期 @workday int -- 要增加的工作日数 ) RETURNS datetime AS BEGIN DECLARE @bz int -- 增加整周的天数 SELECT @bz = CASE WHEN @workday < 0 THEN - 1 ELSE 1 END , @date = DATEADD (Week, @workday / 5 , @date ) , @workday = @workday % 5 -- 增加不是整周的工作天数 WHILE @workday <> 0 SELECT @date = DATEADD ( Day , @bz , @date ), @workday = CASE WHEN ( @@DATEFIRST + DATEPART (Weekday, @date ) - 1 ) % 7 BETWEEN 1 AND 5 THEN @workday - @bz ELSE @workday END -- 避免处理后的日期停留在非工作日上 WHILE ( @@DATEFIRST + DATEPART (Weekday, @date ) - 1 ) % 7 in ( 0 , 6 ) SET @date = DATEADD ( Day , @bz , @date ) RETURN ( @date ) END

工作日处理函数(自定义节假日).sql
SQL code
      
      
if exists ( select * from dbo.sysobjects where id = object_id (N ' [tb_Holiday] ' ) and OBJECTPROPERTY (id, N ' IsUserTable ' ) = 1 ) drop table [ tb_Holiday ] GO -- 定义节假日表 CREATE TABLE tb_Holiday( HDate smalldatetime primary key clustered , -- 节假日期 Name nvarchar ( 50 ) not null ) -- 假日名称 GO if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_WorkDay] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_WorkDay ] GO -- 计算两个日期之间的工作天数 CREATE FUNCTION f_WorkDay( @dt_begin datetime , -- 计算的开始日期 @dt_end datetime -- 计算的结束日期 ) RETURNS int AS BEGIN IF @dt_begin > @dt_end RETURN ( DATEDIFF ( Day , @dt_begin , @dt_end ) + 1 - ( SELECT COUNT ( * ) FROM tb_Holiday WHERE HDate BETWEEN @dt_begin AND @dt_end )) RETURN ( - ( DATEDIFF ( Day , @dt_end , @dt_begin ) + 1 - ( SELECT COUNT ( * ) FROM tb_Holiday WHERE HDate BETWEEN @dt_end AND @dt_begin ))) END GO if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_WorkDayADD] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_WorkDayADD ] GO -- 在指定日期上增加工作天数 CREATE FUNCTION f_WorkDayADD( @date datetime , -- 基础日期 @workday int -- 要增加的工作日数 ) RETURNS datetime AS BEGIN IF @workday > 0 WHILE @workday > 0 SELECT @date = @date + @workday , @workday = count ( * ) FROM tb_Holiday WHERE HDate BETWEEN @date AND @date + @workday ELSE WHILE @workday < 0 SELECT @date = @date + @workday , @workday =- count ( * ) FROM tb_Holiday WHERE HDate BETWEEN @date AND @date + @workday RETURN ( @date ) END

计算工作时间的函数.sql
SQL code
      
      
if exists ( select * from dbo.sysobjects where id = object_id (N ' [tb_worktime] ' ) and OBJECTPROPERTY (id, N ' IsUserTable ' ) = 1 ) drop table [ tb_worktime ] GO -- 定义工作时间表 CREATE TABLE tb_worktime( ID int identity ( 1 , 1 ) PRIMARY KEY , -- 序号 time_start smalldatetime , -- 工作的开始时间 time_end smalldatetime , -- 工作的结束时间 worktime AS DATEDIFF (Minute,time_start,time_end) -- 工作时数(分钟) ) GO if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_WorkTime] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_WorkTime ] GO -- 计算两个日期之间的工作时间 CREATE FUNCTION f_WorkTime( @date_begin datetime , -- 计算的开始时间 @date_end datetime -- 计算的结束时间 ) RETURNS int AS BEGIN DECLARE @worktime int IF DATEDIFF ( Day , @date_begin , @date_end ) = 0 SELECT @worktime = SUM ( DATEDIFF (Minute, CASE WHEN CONVERT ( VARCHAR , @date_begin , 108 ) > time_start THEN CONVERT ( VARCHAR , @date_begin , 108 ) ELSE time_start END , CASE WHEN CONVERT ( VARCHAR , @date_end , 108 ) < time_end THEN CONVERT ( VARCHAR , @date_end , 108 ) ELSE time_end END )) FROM tb_worktime WHERE time_end > CONVERT ( VARCHAR , @date_begin , 108 ) AND time_start < CONVERT ( VARCHAR , @date_end , 108 ) ELSE SET @worktime = ( SELECT SUM ( CASE WHEN CONVERT ( VARCHAR , @date_begin , 108 ) > time_start THEN DATEDIFF (Minute, CONVERT ( VARCHAR , @date_begin , 108 ),time_end) ELSE worktime END ) FROM tb_worktime WHERE time_end > CONVERT ( VARCHAR , @date_begin , 108 )) + ( SELECT SUM ( CASE WHEN CONVERT ( VARCHAR , @date_end , 108 ) < time_end THEN DATEDIFF (Minute,time_start, CONVERT ( VARCHAR , @date_end , 108 )) ELSE worktime END ) FROM tb_worktime WHERE time_start < CONVERT ( VARCHAR , @date_end , 108 )) + CASE WHEN DATEDIFF ( Day , @date_begin , @date_end ) > 1 THEN ( DATEDIFF ( Day , @date_begin , @date_end ) - 1 ) * ( SELECT SUM (worktime) FROM tb_worktime) ELSE 0 END RETURN ( @worktime ) END
复杂年月处理.sql
SQL code
     
     
-- 定义基本数字表 declare @T1 table (代码 int ,名称 varchar ( 10 ),参加时间 datetime ,终止时间 datetime ) insert into @T1 select 12 , ' 单位1 ' , ' 2003/04/01 ' , ' 2004/05/01 ' union all select 22 , ' 单位2 ' , ' 2001/02/01 ' , ' 2003/02/01 ' union all select 42 , ' 单位3 ' , ' 2000/04/01 ' , ' 2003/05/01 ' union all select 25 , ' 单位5 ' , ' 2003/04/01 ' , ' 2003/05/01 ' -- 定义年表 declare @NB table (代码 int ,名称 varchar ( 10 ),年份 int ) insert into @NB select 12 , ' 单位1 ' , 2003 union all select 12 , ' 单位1 ' , 2004 union all select 22 , ' 单位2 ' , 2001 union all select 22 , ' 单位2 ' , 2002 union all select 22 , ' 单位2 ' , 2003 -- 定义月表 declare @YB table (代码 int ,名称 varchar ( 10 ),年份 int ,月份 varchar ( 2 )) insert into @YB select 12 , ' 单位1 ' , 2003 , ' 04 ' union all select 22 , ' 单位2 ' , 2001 , ' 01 ' union all select 22 , ' 单位2 ' , 2001 , ' 12 ' -- 为年表+月表数据处理准备临时表 select top 8246 y = identity ( int , 1753 , 1 ) into #tby from ( select id from syscolumns) a, ( select id from syscolumns) b, ( select id from syscolumns) c -- 为月表数据处理准备临时表 select top 12 m = identity ( int , 1 , 1 ) into #tbm from syscolumns /* --数据处理-- */ -- 年表数据处理 select a. * from ( select a.代码,a.名称,年份 = b.y from @T1 a,#tby b where b.y between year (参加时间) and year (终止时间) ) a left join @NB b on a.代码 = b.代码 and a.年份 = b.年份 where b.代码 is null -- 月表数据处理 select a. * from ( select a.代码,a.名称,年份 = b.y,月份 =right ( ' 00 ' + cast (c.m as varchar ), 2 ) from @T1 a,#tby b,#tbm c where b.y * 100 + c.m between convert ( varchar ( 6 ),参加时间, 112 ) and convert ( varchar ( 6 ),终止时间, 112 ) ) a left join @YB b on a.代码 = b.代码 and a.年份 = b.年份 and a.月份 = b.月份 where b.代码 is null order by a.代码,a.名称,a.年份,a.月份 -- 删除数据处理临时表 drop table #tby,#tbm

交叉表.sql
SQL code
     
     
-- 示例 -- 示例数据 create table tb(ID int ,Time datetime ) insert tb select 1 , ' 2005/01/24 16:20 ' union all select 2 , ' 2005/01/23 22:45 ' union all select 3 , ' 2005/01/23 0:30 ' union all select 4 , ' 2005/01/21 4:28 ' union all select 5 , ' 2005/01/20 13:22 ' union all select 6 , ' 2005/01/19 20:30 ' union all select 7 , ' 2005/01/19 18:23 ' union all select 8 , ' 2005/01/18 9:14 ' union all select 9 , ' 2005/01/18 18:04 ' go -- 查询处理: select case when grouping (b.Time) = 1 then ' Total ' else b.Time end , [ Mon ] = sum ( case a.week when 1 then 1 else 0 end ), [ Tue ] = sum ( case a.week when 2 then 1 else 0 end ), [ Wed ] = sum ( case a.week when 3 then 1 else 0 end ), [ Thu ] = sum ( case a.week when 4 then 1 else 0 end ), [ Fri ] = sum ( case a.week when 5 then 1 else 0 end ), [ Sat ] = sum ( case a.week when 6 then 1 else 0 end ), [ Sun ] = sum ( case a.week when 0 then 1 else 0 end ), [ Total ] = count (a.week) from ( select Time = convert ( char ( 5 ), dateadd (hour, - 1 ,Time), 108 ) -- 时间交界点是1am,所以减1小时,避免进行跨天处理 ,week = ( @@datefirst + datepart (weekday,Time) - 1 ) % 7 -- 考虑@@datefirst对datepart的影响 from tb )a right join ( select id = 1 ,a = ' 16:00 ' ,b = ' 19:59 ' ,Time = ' [5pm - 9pm) ' union all select id = 2 ,a = ' 20:00 ' ,b = ' 23:59 ' ,Time = ' [9pm - 1am) ' union all select id = 3 ,a = ' 00:00 ' ,b = ' 02:59 ' ,Time = ' [1am - 4am) ' union all select id = 4 ,a = ' 03:00 ' ,b = ' 07:29 ' ,Time = ' [4am - 8:30am) ' union all select id = 5 ,a = ' 07:30 ' ,b = ' 11:59 ' ,Time = ' [8:30am - 1pm) ' union all select id = 6 ,a = ' 12:00 ' ,b = ' 15:59 ' ,Time = ' [1pm - 5pm) ' )b on a.Time >= b.a and a.Time < b.b group by b.id,b.Time with rollup having grouping (b.Time) = 0 or grouping (b.id) = 1 go -- 删除测试 drop table tb /* --测试结果 Mon Tue Wed Thu Fri Sat Sun Total -------------- ----- ----- ----- ----- ----- ------ ---- ------- [5pm - 9pm) 0 1 2 0 0 0 0 3 [9pm - 1am) 0 0 0 0 0 0 2 2 [1am - 4am) 0 0 0 0 0 0 0 0 [4am - 8:30am) 0 0 0 0 1 0 0 1 [8:30am - 1pm) 0 1 0 0 0 0 0 1 [1pm - 5pm) 1 0 0 1 0 0 0 2 Total 1 2 2 1 1 0 2 9 (所影响的行数为 7 行) -- */

任意两个时间之间的星期几的次数-横.sql
SQL code
     
     
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_weekdaycount] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_weekdaycount ] GO /* --计算任意两个时间之间的星期几的次数(横向显示) 本方法直接判断 @@datefirst 做对应处理 不受 sp_language 及 set datefirst 的影响 --邹建 2004.08(引用请保留此信息)-- */ /* --调用示例 select * from f_weekdaycount('2004-9-01','2004-9-02') -- */ create function f_weekdaycount( @dt_begin datetime , @dt_end datetime ) returns table as return ( select 跨周数 ,周一 = case a when - 1 then case when 1 between b and c then 1 else 0 end when 0 then case when b <= 1 then 1 else 0 end + case when c >= 1 then 1 else 0 end else a + case when b <= 1 then 1 else 0 end + case when c >= 1 then 1 else 0 end end ,周二 = case a when - 1 then case when 2 between b and c then 1 else 0 end when 0 then case when b <= 2 then 1 else 0 end + case when c >= 2 then 1 else 0 end else a + case when b <= 2 then 1 else 0 end + case when c >= 2 then 1 else 0 end end ,周三 = case a when - 1 then case when 3 between b and c then 1 else 0 end when 0 then case when b <= 3 then 1 else 0 end + case when c >= 3 then 1 else 0 end else a + case when b <= 3 then 1 else 0 end + case when c >= 3 then 1 else 0 end end ,周四 = case a when - 1 then case when 4 between b and c then 1 else 0 end when 0 then case when b <= 4 then 1 else 0 end + case when c >= 4 then 1 else 0 end else a + case when b <= 4 then 1 else 0 end + case when c >= 4 then 1 else 0 end end ,周五 = case a when - 1 then case when 5 between b and c then 1 else 0 end when 0 then case when b <= 5 then 1 else 0 end + case when c >= 5 then 1 else 0 end else a + case when b <= 5 then 1 else 0 end + case when c >= 5 then 1 else 0 end end ,周六 = case a when - 1 then case when 6 between b and c then 1 else 0 end when 0 then case when b <= 6 then 1 else 0 end + case when c >= 6 then 1 else 0 end else a + case when b <= 6 then 1 else 0 end + case when c >= 6 then 1 else 0 end end ,周日 = case a when - 1 then case when 0 between b and c then 1 else 0 end when 0 then case when b <= 0 then 1 else 0 end + case when c >= 0 then 1 else 0 end else a + case when b <= 0 then 1 else 0 end + case when c >= 0 then 1 else 0 end end from ( select 跨周数 = case when @dt_begin < @dt_end then ( datediff ( day , @dt_begin , @dt_end ) + 7 ) / 7 else ( datediff ( day , @dt_end , @dt_begin ) + 7 ) / 7 end ,a = case when @dt_begin < @dt_end then datediff (week, @dt_begin , @dt_end ) - 1 else datediff (week, @dt_end , @dt_begin ) - 1 end ,b = case when @dt_begin < @dt_end then ( @@datefirst + datepart (weekday, @dt_begin ) - 1 ) % 7 else ( @@datefirst + datepart (weekday, @dt_end ) - 1 ) % 7 end ,c = case when @dt_begin < @dt_end then ( @@datefirst + datepart (weekday, @dt_end ) - 1 ) % 7 else ( @@datefirst + datepart (weekday, @dt_begin ) - 1 ) % 7 end )a ) go
     
     
统计--交叉表+日期+优先.sql
SQL code
        
        
-- 交叉表,根据优先级取数据,日期处理 create table tb(qid int ,rid nvarchar ( 4 ),tagname nvarchar ( 10 ),starttime smalldatetime ,endtime smalldatetime ,startweekday int ,endweekday int ,startdate smalldatetime ,enddate smalldatetime ,d int ) insert tb select 1 , ' A1 ' , ' 未订 ' , ' 08:00 ' , ' 09:00 ' , 1 , 5 , null , null , 1 union all select 1 , ' A1 ' , ' 未订 ' , ' 09:00 ' , ' 10:00 ' , 1 , 5 , null , null , 1 union all select 1 , ' A1 ' , ' 未订 ' , ' 10:00 ' , ' 11:00 ' , 1 , 5 , null , null , 1 union all select 1 , ' A1 ' , ' 装修 ' , ' 08:00 ' , ' 09:00 ' , null , null , ' 2005-1-18 ' , ' 2005-1-19 ' , 2 -- union all select 1,'A1','装修','09:00','10:00',null,null,'2005-1-18','2005-1-19',2 union all select 1 , ' A1 ' , ' 装修 ' , ' 10:00 ' , ' 11:00 ' , null , null , ' 2005-1-18 ' , ' 2005-1-19 ' , 2 union all select 1 , ' A2 ' , ' 未订 ' , ' 08:00 ' , ' 09:00 ' , 1 , 5 , null , null , 1 union all select 1 , ' A2 ' , ' 未订 ' , ' 09:00 ' , ' 10:00 ' , 1 , 5 , null , null , 1 union all select 1 , ' A2 ' , ' 未订 ' , ' 10:00 ' , ' 11:00 ' , 1 , 5 , null , null , 1 -- union all select 1,'A2','装修','08:00','09:00',null,null,'2005-1-18','2005-1-19',2 union all select 1 , ' A2 ' , ' 装修 ' , ' 09:00 ' , ' 10:00 ' , null , null , ' 2005-1-18 ' , ' 2005-1-19 ' , 2 -- union all select 1,'A2','装修','10:00','11:00',null,null,'2005-1-18','2005-1-19',2 go /* --楼主这个问题要考虑几个方面 1. 取星期时,set datefirst 的影响 2. 优先级问题 3. qid,rid 应该是未知的(动态变化的) -- */ -- 实现的存储过程如下 create proc p_qry @date smalldatetime -- 要查询的日期 as set nocount on declare @week int , @s nvarchar ( 4000 ) -- 格式化日期和得到星期 select @date = convert ( char ( 10 ), @date , 120 ) , @week = ( @@datefirst + datepart (weekday, @date ) - 1 ) % 7 , @s = '' select id = identity ( int ), * into #t from ( select top 100 percent qid,rid,tagname, starttime = convert ( char ( 5 ),starttime, 108 ), endtime = convert ( char ( 5 ),endtime, 108 ) from tb where ( @week between startweekday and endweekday) or ( @date between startdate and enddate) order by qid,rid,starttime,d desc )a select @s = @s + N ' ,[ ' + rtrim (rid) + N ' ]=max(case when qid= ' + rtrim (qid) + N ' and rid=N ''' + rtrim (rid) + N ''' then tagname else N '''' end) ' from #t group by qid,rid exec ( ' select starttime,endtime ' + @s + ' from #t a where not exists( select * from #t where qid=a.qid and rid=a.rid and starttime=a.starttime and endtime=a.endtime and id<a.id) group by starttime,endtime ' ) go -- 调用 exec p_qry ' 2005-1-17 ' exec p_qry ' 2005-1-18 ' go -- 删除测试 drop table tb drop proc p_qry /* --测试结果 starttime endtime A1 A2 --------- ------- ---------- ---------- 08:00 09:00 未订 未订 09:00 10:00 未订 未订 10:00 11:00 未订 未订 starttime endtime A1 A2 --------- ------- ---------- ---------- 08:00 09:00 装修 未订 09:00 10:00 未订 装修 10:00 11:00 装修 未订 -- */

各种字符串分拆处理函数.sql
SQL code
        
        
-- 各种字符串分函数 if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_splitSTR] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_splitSTR ] GO -- 3.2.1 循环截取法 CREATE FUNCTION f_splitSTR( @s varchar ( 8000 ), -- 待分拆的字符串 @split varchar ( 10 ) -- 数据分隔符 ) RETURNS @re TABLE (col varchar ( 100 )) AS BEGIN DECLARE @splitlen int SET @splitlen = LEN ( @split + ' a ' ) - 2 WHILE CHARINDEX ( @split , @s ) > 0 BEGIN INSERT @re VALUES ( LEFT ( @s , CHARINDEX ( @split , @s ) - 1 )) SET @s = STUFF ( @s , 1 , CHARINDEX ( @split , @s ) + @splitlen , '' ) END INSERT @re VALUES ( @s ) RETURN END GO /* ============================================== */ if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_splitSTR] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_splitSTR ] GO -- 3.2.3.1 使用临时性分拆辅助表法 CREATE FUNCTION f_splitSTR( @s varchar ( 8000 ), -- 待分拆的字符串 @split varchar ( 10 ) -- 数据分隔符 ) RETURNS @re TABLE (col varchar ( 100 )) AS BEGIN -- 创建分拆处理的辅助表(用户定义函数中只能操作表变量) DECLARE @t TABLE (ID int IDENTITY ,b bit ) INSERT @t (b) SELECT TOP 8000 0 FROM syscolumns a,syscolumns b INSERT @re SELECT SUBSTRING ( @s ,ID, CHARINDEX ( @split , @s + @split ,ID) - ID) FROM @t WHERE ID <= LEN ( @s + ' a ' ) AND CHARINDEX ( @split , @split + @s ,ID) = ID RETURN END GO /* ============================================== */ if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_splitSTR] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_splitSTR ] GO if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[tb_splitSTR] ' ) and objectproperty (id,N ' IsUserTable ' ) = 1 ) drop table [ dbo ] . [ tb_splitSTR ] GO -- 3.2.3.2 使用永久性分拆辅助表法 -- 字符串分拆辅助表 SELECT TOP 8000 ID = IDENTITY ( int , 1 , 1 ) INTO dbo.tb_splitSTR FROM syscolumns a,syscolumns b GO -- 字符串分拆处理函数 CREATE FUNCTION f_splitSTR( @s varchar ( 8000 ), -- 待分拆的字符串 @split varchar ( 10 ) -- 数据分隔符 ) RETURNS TABLE AS RETURN ( SELECT col = CAST ( SUBSTRING ( @s ,ID, CHARINDEX ( @split , @s + @split ,ID) - ID) as varchar ( 100 )) FROM tb_splitSTR WHERE ID <= LEN ( @s + ' a ' ) AND CHARINDEX ( @split , @split + @s ,ID) = ID) GO /* ============================================== */ if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_splitSTR] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_splitSTR ] GO -- 3.2.5 将数据项按数字与非数字再次拆份 CREATE FUNCTION f_splitSTR( @s varchar ( 8000 ), -- 待分拆的字符串 @split varchar ( 10 ) -- 数据分隔符 ) RETURNS @re TABLE (No varchar ( 100 ),Value varchar ( 20 )) AS BEGIN -- 创建分拆处理的辅助表(用户定义函数中只能操作表变量) DECLARE @t TABLE (ID int IDENTITY ,b bit ) INSERT @t (b) SELECT TOP 8000 0 FROM syscolumns a,syscolumns b INSERT @re SELECT No = REVERSE ( STUFF (col, 1 , PATINDEX ( ' %[^-^.^0-9]% ' ,col + ' a ' ) - 1 , '' )), Value = REVERSE ( LEFT (col, PATINDEX ( ' %[^-^.^0-9]% ' ,col + ' a ' ) - 1 )) FROM ( SELECT col = REVERSE ( SUBSTRING ( @s ,ID, CHARINDEX ( @split , @s + @split ,ID) - ID)) FROM @t WHERE ID <= LEN ( @s + ' a ' ) AND CHARINDEX ( @split , @split + @s ,ID) = ID)a RETURN END GO /* ============================================== */ if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_splitSTR] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' )) drop function [ dbo ] . [ f_splitSTR ] GO -- 3.2.6 分拆短信数据 CREATE FUNCTION f_splitSTR( @s varchar ( 8000 )) RETURNS @re TABLE (split varchar ( 10 ),value varchar ( 100 )) AS BEGIN DECLARE @splits TABLE (split varchar ( 10 ),splitlen as LEN (split)) INSERT @splits (split) SELECT ' AC ' UNION ALL SELECT ' BC ' UNION ALL SELECT ' CC ' UNION ALL SELECT ' DC ' DECLARE @pos1 int , @pos2 int , @split varchar ( 10 ), @splitlen int SELECT TOP 1 @pos1 = 1 , @split = split, @splitlen = splitlen FROM @splits WHERE @s LIKE split + ' % ' WHILE @pos1 > 0 BEGIN SELECT TOP 1 @pos2 = CHARINDEX (split, @s , @splitlen + 1 ) FROM @splits WHERE CHARINDEX (split, @s , @splitlen + 1 ) > 0 ORDER BY CHARINDEX (split, @s , @splitlen + 1 ) IF @@ROWCOUNT = 0 BEGIN INSERT @re VALUES ( @split , STUFF ( @s , 1 , @splitlen , '' )) RETURN END ELSE BEGIN INSERT @re VALUES ( @split , SUBSTRING ( @s , @splitlen + 1 , @pos2 - @splitlen - 1 )) SELECT TOP 1 @pos1 = 1 , @split = split, @splitlen = splitlen, @s = STUFF ( @s , 1 , @pos2 - 1 , '' ) FROM @splits WHERE STUFF ( @s , 1 , @pos2 - 1 , '' ) LIKE split + ' % ' END END RETURN END GO
      
      
各种字符串合并处理示例.sql
SQL code
          
          
-- 各种字符串分函数 -- 3.3.1 使用游标法进行字符串合并处理的示例。 -- 处理的数据 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 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 -- 显示结果并删除测试数据 SELECT * FROM @t DROP TABLE tb /* --结果 col1 col2 ---------- ----------- a 1,2 b 1,2,3 -- */ GO /* ============================================== */ -- 3.3.2 使用用户定义函数,配合SELECT处理完成字符串合并处理的示例 -- 处理的数据 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 GO -- 合并处理函数 CREATE FUNCTION dbo.f_str( @col1 varchar ( 10 )) RETURNS varchar ( 100 ) AS BEGIN DECLARE @re varchar ( 100 ) SET @re = '' SELECT @re = @re + ' , ' + CAST (col2 as varchar ) FROM tb WHERE col1 = @col1 RETURN ( STUFF ( @re , 1 , 1 , '' )) END GO -- 调用函数 SELECT col1,col2 = dbo.f_str(col1) FROM tb GROUP BY col1 -- 删除测试 DROP TABLE tb DROP FUNCTION f_str /* --结果 col1 col2 ---------- ----------- a 1,2 b 1,2,3 -- */ GO /* ============================================== */ -- 3.3.3 使用临时表实现字符串合并处理的示例 -- 处理的数据 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 -- 合并处理 SELECT col1,col2 = CAST (col2 as varchar ( 100 )) INTO #t FROM tb ORDER BY col1,col2 DECLARE @col1 varchar ( 10 ), @col2 varchar ( 100 ) UPDATE #t SET @col2 = CASE WHEN @col1 = col1 THEN @col2 + ' , ' + col2 ELSE col2 END , @col1 = col1, col2 = @col2 SELECT * FROM #t /* --更新处理后的临时表 col1 col2 ---------- ------------- a 1 a 1,2 b 1 b 1,2 b 1,2,3 -- */ -- 得到最终结果 SELECT col1,col2 = MAX (col2) FROM #t GROUP BY col1 /* --结果 col1 col2 ---------- ----------- a 1,2 b 1,2,3 -- */ -- 删除测试 DROP TABLE tb,#t GO /* ============================================== */ -- 3.3.4.1 每组 <=2 条记录的合并 -- 处理的数据 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 ' c ' , 3 -- 合并处理 SELECT col1, col2 = CAST ( MIN (col2) as varchar ) + CASE WHEN COUNT ( * ) = 1 THEN '' ELSE ' , ' + CAST ( MAX (col2) as varchar ) END FROM tb GROUP BY col1 DROP TABLE tb /* --结果 col1 col2 ---------- ---------- a 1,2 b 1,2 c 3 -- */ -- 3.3.4.2 每组 <=3 条记录的合并 -- 处理的数据 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 UNION ALL SELECT ' c ' , 3 -- 合并处理 SELECT col1, col2 = CAST ( MIN (col2) as varchar ) + CASE WHEN COUNT ( * ) = 3 THEN ' , ' + CAST (( SELECT col2 FROM tb WHERE col1 = a.col1 AND col2 NOT IN ( MAX (a.col2), MIN (a.col2))) as varchar ) ELSE '' END + CASE WHEN COUNT ( * ) >= 2 THEN ' , ' + CAST ( MAX (col2) as varchar ) ELSE '' END FROM tb a GROUP BY col1 DROP TABLE tb /* --结果 col1 col2 ---------- ------------ a 1,2 b 1,2,3 c 3 -- */ GO
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值