zoukankan      html  css  js  c++  java
  • 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


  • 相关阅读:
    JS中短路运算符&&和||
    jadx 调整jvm参数
    python 面向对象(进阶篇)
    Python 面向对象(初级篇)
    python+requests接口自动化测试实战
    Jmeter-接口压测
    敬请指正-我进行单元测试的分享
    现在的开发都要懂测试了,为什么?这一份书单告诉你!
    你不得不看-自动化测试工程师面试总结:技术面试
    web自动化快速使用
  • 原文地址:https://www.cnblogs.com/tonybinlj/p/1437849.html
Copyright © 2011-2022 走看看