设为首页收藏本站Access中国

Office中国论坛/Access中国论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

返回列表 发新帖
查看: 4417|回复: 7
打印 上一主题 下一主题

日期相关的SQL大全

[复制链接]
跳转到指定楼层
1#
发表于 2011-11-17 23:18:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1.日期概念理解中的一些测试.sql:
  1. SQL code
  2. --A. 测试 datetime 精度问题
  3. DECLARE @t TABLE(date char(21))
  4. INSERT @t SELECT '1900-1-1 00:00:00.000'
  5. INSERT @t SELECT '1900-1-1 00:00:00.001'
  6. INSERT @t SELECT '1900-1-1 00:00:00.009'
  7. INSERT @t SELECT '1900-1-1 00:00:00.002'
  8. INSERT @t SELECT '1900-1-1 00:00:00.003'
  9. INSERT @t SELECT '1900-1-1 00:00:00.004'
  10. INSERT @t SELECT '1900-1-1 00:00:00.005'
  11. INSERT @t SELECT '1900-1-1 00:00:00.006'
  12. INSERT @t SELECT '1900-1-1 00:00:00.007'
  13. INSERT @t SELECT '1900-1-1 00:00:00.008'
  14. SELECT date,转换后的日期=CAST(date as datetime) FROM @t

  15. /*--结果

  16. date                  转换后的日期
  17. --------------------- --------------------------
  18. 1900-1-1 00:00:00.000 1900-01-01 00:00:00.000
  19. 1900-1-1 00:00:00.001 1900-01-01 00:00:00.000
  20. 1900-1-1 00:00:00.009 1900-01-01 00:00:00.010
  21. 1900-1-1 00:00:00.002 1900-01-01 00:00:00.003
  22. 1900-1-1 00:00:00.003 1900-01-01 00:00:00.003
  23. 1900-1-1 00:00:00.004 1900-01-01 00:00:00.003
  24. 1900-1-1 00:00:00.005 1900-01-01 00:00:00.007
  25. 1900-1-1 00:00:00.006 1900-01-01 00:00:00.007
  26. 1900-1-1 00:00:00.007 1900-01-01 00:00:00.007
  27. 1900-1-1 00:00:00.008 1900-01-01 00:00:00.007

  28. (所影响的行数为 10 行)
  29. --*/
  30. GO

  31. --B. 对于 datetime 类型的纯日期和时间的十六进制表示
  32. DECLARE @dt datetime

  33. --单纯的日期
  34. SET @dt='1900-1-2'
  35. SELECT CAST(@dt as binary(8))
  36. --结果: 0x0000000100000000

  37. --单纯的时间
  38. SET @dt='00:00:01'
  39. SELECT CAST(@dt as binary(8))
  40. --结果: 0x000000000000012C
  41. GO

  42. --C. 对于 smalldatetime 类型的纯日期和时间的十六进制表示
  43. DECLARE @dt smalldatetime

  44. --单纯的日期
  45. SET @dt='1900-1-2'
  46. SELECT CAST(@dt as binary(4))
  47. --结果: 0x00010000

  48. --单纯的时间
  49. SET @dt='00:10'
  50. SELECT CAST(@dt as binary(4))
  51. --结果: 0x0000000A


复制代码
2.CONVERT在日期转换中的使用示例.sql:
  1. SQL code
  2. --字符转换为日期时,Style的使用

  3. --1. Style=101时,表示日期字符串为:mm/dd/yyyy格式
  4. SELECT CONVERT(datetime,'11/1/2003',101)
  5. --结果:2003-11-01 00:00:00.000

  6. --2. Style=101时,表示日期字符串为:dd/mm/yyyy格式
  7. SELECT CONVERT(datetime,'11/1/2003',103)
  8. --结果:2003-01-11 00:00:00.000


  9. /*== 日期转换为字符串 ==*/
  10. DECLARE @dt datetime
  11. SET @dt='2003-1-11'

  12. --1. Style=101时,表示将日期转换为:mm/dd/yyyy 格式
  13. SELECT CONVERT(varchar,@dt,101)
  14. --结果:01/11/2003

  15. --2. Style=103时,表示将日期转换为:dd/mm/yyyy 格式
  16. SELECT CONVERT(varchar,@dt,103)
  17. --结果:11/01/2003

  18. /*== 这是很多人经常犯的错误,对非日期型转换使用日期的style样式 ==*/
  19. SELECT CONVERT(varchar,'2003-1-11',101)
  20. --结果:2003-1-11


复制代码
3.SET DATEFORMAT对日期处理的影响.sql
  1. SQL code
  2. --1.
  3. /*--说明
  4.     SET DATEFORMAT设置对使用CONVERT把字符型日期转换为日期的处理也具有影响
  5.     但不影响明确指定了style的CONVERT处理。
  6. --*/

  7. --示例 ,在下面的示例中,第一个CONVERT转换未指定style,转换的结果受SET DATAFORMAT的影响,第二个CONVERT转换指定了style,转换结果受style的影响。
  8. --设置输入日期顺序为 日/月/年
  9. SET DATEFORMAT DMY

  10. --不指定Style参数的CONVERT转换将受到SET DATEFORMAT的影响
  11. SELECT CONVERT(datetime,'2-1-2005')
  12. --结果: 2005-01-02 00:00:00.000

  13. --指定Style参数的CONVERT转换不受SET DATEFORMAT的影响
  14. SELECT CONVERT(datetime,'2-1-2005',101)
  15. --结果: 2005-02-01 00:00:00.000
  16. GO

  17. --2.
  18. /*--说明

  19.     如果输入的日期包含了世纪部分,则对日期进行解释处理时
  20.     年份的解释不受SET DATEFORMAT设置的影响。
  21. --*/

  22. --示例,在下面的代码中,同样的SET DATEFORMAT设置,输入日期的世纪部分与不输入日期的世纪部分,解释的日期结果不同。
  23. DECLARE @dt datetime

  24. --设置SET DATEFORMAT为:月日年
  25. SET DATEFORMAT MDY

  26. --输入的日期中指定世纪部分
  27. SET @dt='01-2002-03'
  28. SELECT @dt
  29. --结果: 2002-01-03 00:00:00.000

  30. --输入的日期中不指定世纪部分
  31. SET @dt='01-02-03'
  32. SELECT @dt
  33. --结果: 2003-01-02 00:00:00.000
  34. GO

  35. --3.
  36. /*--说明

  37.     如果输入的日期不包含日期分隔符,那么SQL Server在对日期进行解释时
  38.     将忽略SET DATEFORMAT的设置。
  39. --*/

  40. --示例,在下面的代码中,不包含日期分隔符的字符日期,在不同的SET DATEFORMAT设置下,其解释的结果是一样的。
  41. DECLARE @dt datetime

  42. --设置SET DATEFORMAT为:月日年
  43. SET DATEFORMAT MDY
  44. SET @dt='010203'
  45. SELECT @dt
  46. --结果: 2001-02-03 00:00:00.000

  47. --设置SET DATEFORMAT为:日月年
  48. SET DATEFORMAT DMY
  49. SET @dt='010203'
  50. SELECT @dt
  51. --结果: 2001-02-03 00:00:00.000

  52. --输入的日期中包含日期分隔符
  53. SET @dt='01-02-03'
  54. SELECT @dt
  55. --结果: 2003-02-01 00:00:00.000


复制代码
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享分享 分享淘帖 订阅订阅
2#
 楼主| 发表于 2011-11-17 23:20:44 | 只看该作者
4.SET LANGUAGE对日期处理的影响示例.sql
  1. SQL code
  2. --以下示例演示了在不同的语言环境(SET LANGUAGE)下,DATENAME与CONVERT函数的不同结果。
  3. USE master

  4. --设置会话的语言环境为: English
  5. SET LANGUAGE N'English'
  6. SELECT
  7.     DATENAME(Month,GETDATE()) AS [Month],
  8.     DATENAME(Weekday,GETDATE()) AS [Weekday],
  9.     CONVERT(varchar,GETDATE(),109) AS [CONVERT]
  10. /*--结果:
  11. Month    Weekday   CONVERT
  12. ------------- -------------- -------------------------------
  13. March    Tuesday   Mar 15 2005  8:59PM
  14. --*/

  15. --设置会话的语言环境为: 简体中文
  16. SET LANGUAGE N'简体中文'
  17. SELECT
  18.     DATENAME(Month,GETDATE()) AS [Month],
  19.     DATENAME(Weekday,GETDATE()) AS [Weekday],
  20.     CONVERT(varchar,GETDATE(),109) AS [CONVERT]
  21. /*--结果
  22. Month    Weekday    CONVERT
  23. ------------- --------------- -----------------------------------------
  24. 05       星期四     05 19 2005  2:49:20:607PM
  25. --*/


复制代码
5.日期格式化处理.sql
  1. SQL code
  2. DECLARE @dt datetime
  3. SET @dt=GETDATE()

  4. --1.短日期格式:yyyy-m-d
  5. SELECT REPLACE(CONVERT(varchar(10),@dt,120),N'-0','-')

  6. --2.长日期格式:yyyy年mm月dd日
  7. --A. 方法1
  8. SELECT STUFF(STUFF(CONVERT(char(8),@dt,112),5,0,N'年'),8,0,N'月')+N'日'
  9. --B. 方法2
  10. SELECT DATENAME(Year,@dt)+N'年'+DATENAME(Month,@dt)+N'月'+DATENAME(Day,@dt)+N'日'

  11. --3.长日期格式:yyyy年m月d日
  12. SELECT DATENAME(Year,@dt)+N'年'+CAST(DATEPART(Month,@dt) AS varchar)+N'月'+DATENAME(Day,@dt)+N'日'

  13. --4.完整日期+时间格式:yyyy-mm-dd hh:mi:ss:mmm
  14. SELECT CONVERT(char(11),@dt,120)+CONVERT(char(12),@dt,114)


复制代码
6.日期推算处理.sql
  1. SQL code
  2. DECLARE @dt datetime
  3. SET @dt=GETDATE()

  4. DECLARE @number int
  5. SET @number=3

  6. --1.指定日期该年的第一天或最后一天
  7. --A. 年的第一天
  8. SELECT CONVERT(char(5),@dt,120)+'1-1'

  9. --B. 年的最后一天
  10. SELECT CONVERT(char(5),@dt,120)+'12-31'


  11. --2.指定日期所在季度的第一天或最后一天
  12. --A. 季度的第一天
  13. SELECT CONVERT(datetime,
  14.     CONVERT(char(8),
  15.         DATEADD(Month,
  16.             DATEPART(Quarter,@dt)*3-Month(@dt)-2,
  17.             @dt),
  18.         120)+'1')

  19. --B. 季度的最后一天(CASE判断法)
  20. SELECT CONVERT(datetime,
  21.     CONVERT(char(8),
  22.         DATEADD(Month,
  23.             DATEPART(Quarter,@dt)*3-Month(@dt),
  24.             @dt),
  25.         120)
  26.     +CASE WHEN DATEPART(Quarter,@dt) in(1,4)
  27.         THEN '31'ELSE '30' END)

  28. --C. 季度的最后一天(直接推算法)
  29. SELECT DATEADD(Day,-1,
  30.     CONVERT(char(8),
  31.         DATEADD(Month,
  32.             1+DATEPART(Quarter,@dt)*3-Month(@dt),
  33.             @dt),
  34.         120)+'1')


  35. --3.指定日期所在月份的第一天或最后一天
  36. --A. 月的第一天
  37. SELECT CONVERT(datetime,CONVERT(char(8),@dt,120)+'1')

  38. --B. 月的最后一天
  39. SELECT DATEADD(Day,-1,CONVERT(char(8),DATEADD(Month,1,@dt),120)+'1')

  40. --C. 月的最后一天(容易使用的错误方法)
  41. SELECT DATEADD(Month,1,DATEADD(Day,-DAY(@dt),@dt))


  42. --4.指定日期所在周的任意一天
  43. SELECT DATEADD(Day,@number-DATEPART(Weekday,@dt),@dt)


  44. --5.指定日期所在周的任意星期几
  45. --A.  星期天做为一周的第1天
  46. SELECT DATEADD(Day,@number-(DATEPART(Weekday,@dt)+@@DATEFIRST-1)%7,@dt)

  47. --B.  星期一做为一周的第1天
  48. SELECT DATEADD(Day,@number-(DATEPART(Weekday,@dt)+@@DATEFIRST-2)%7-1,@dt)

复制代码
3#
 楼主| 发表于 2011-11-17 23:23:00 | 只看该作者
7.特殊日期加减函数.sql
  1. SQL code
  2. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_DateADD]') and xtype in (N'FN', N'IF', N'TF'))
  3.     drop function [dbo].[f_DateADD]
  4. GO

  5. /*--特殊日期加减函数

  6.     对于日期指定部分的加减,使用DATEADD函数就可以轻松实现。
  7.     在实际的处理中,还有一种比较另类的日期加减处理
  8.     就是在指定的日期中,加上(或者减去)多个日期部分
  9.     比如将2005年3月11日,加上1年3个月11天2小时。
  10.     对于这种日期的加减处理,DATEADD函数的力量就显得有点不够。

  11.     本函数实现这样格式的日期字符串加减处理:
  12.     y-m-d h:m:s.m | -y-m-d h:m:s.m
  13.     说明:
  14.     要加减的日期字符输入方式与日期字符串相同。日期与时间部分用空格分隔
  15.     最前面一个字符如果是减号(-)的话,表示做减法处理,否则做加法处理。
  16.     如果日期字符只包含数字,则视为日期字符中,仅包含天的信息。
  17. --*/

  18. /*--调用示例

  19.     SELECT dbo.f_DateADD(GETDATE(),'11:10')
  20. --*/

  21. CREATE FUNCTION dbo.f_DateADD(
  22. @Date     datetime,
  23. @DateStr   varchar(23)
  24. )RETURNS datetime
  25. AS
  26. BEGIN
  27.     DECLARE @bz int,@s varchar(12),@i int

  28.     IF @DateStr IS NULL OR @Date IS NULL
  29.         OR(CHARINDEX('.',@DateStr)>0
  30.             AND @DateStr NOT LIKE '%[:]%[:]%.%')
  31.         RETURN(NULL)
  32.     IF @DateStr='' RETURN(@Date)

  33.     SELECT @bz=CASE
  34.             WHEN LEFT(@DateStr,1)='-' THEN -1
  35.             ELSE 1 END,
  36.         @DateStr=CASE
  37.             WHEN LEFT(@Date,1)='-'
  38.             THEN STUFF(RTRIM(LTRIM(@DateStr)),1,1,'')
  39.             ELSE RTRIM(LTRIM(@DateStr)) END

  40.     IF CHARINDEX(' ',@DateStr)>1
  41.         OR CHARINDEX('-',@DateStr)>1
  42.         OR(CHARINDEX('.',@DateStr)=0
  43.             AND CHARINDEX(':',@DateStr)=0)
  44.     BEGIN
  45.         SELECT @i=CHARINDEX(' ',@DateStr+' ')
  46.             ,@s=REVERSE(LEFT(@DateStr,@i-1))+'-'
  47.             ,@DateStr=STUFF(@DateStr,1,@i,'')
  48.             ,@i=0
  49.         WHILE @s>'' and @i<3
  50.             SELECT @Date=CASE @i
  51.                     WHEN 0 THEN DATEADD(Day,@bz*REVERSE(LEFT(@s,CHARINDEX('-',@s)-1)),@Date)
  52.                     WHEN 1 THEN DATEADD(Month,@bz*REVERSE(LEFT(@s,CHARINDEX('-',@s)-1)),@Date)
  53.                     WHEN 2 THEN DATEADD(Year,@bz*REVERSE(LEFT(@s,CHARINDEX('-',@s)-1)),@Date)
  54.                 END,
  55.                 @s=STUFF(@s,1,CHARINDEX('-',@s),''),
  56.                 @i=@i+1               
  57.     END
  58.     IF @DateStr>''
  59.     BEGIN
  60.         IF CHARINDEX('.',@DateStr)>0
  61.             SELECT @Date=DATEADD(Millisecond
  62.                     ,@bz*STUFF(@DateStr,1,CHARINDEX('.',@DateStr),''),
  63.                     @Date),
  64.                 @DateStr=LEFT(@DateStr,CHARINDEX('.',@DateStr)-1)+':',
  65.                 @i=0
  66.         ELSE
  67.             SELECT @DateStr=@DateStr+':',@i=0
  68.         WHILE @DateStr>'' and @i<3
  69.             SELECT @Date=CASE @i
  70.                     WHEN 0 THEN DATEADD(Hour,@bz*LEFT(@DateStr,CHARINDEX(':',@DateStr)-1),@Date)
  71.                     WHEN 1 THEN DATEADD(Minute,@bz*LEFT(@DateStr,CHARINDEX(':',@DateStr)-1),@Date)
  72.                     WHEN 2 THEN DATEADD(Second,@bz*LEFT(@DateStr,CHARINDEX(':',@DateStr)-1),@Date)
  73.                 END,
  74.                 @DateStr=STUFF(@DateStr,1,CHARINDEX(':',@DateStr),''),
  75.                 @i=@i+1
  76.     END

  77.     RETURN(@Date)
  78. END
  79. GO


复制代码
8.查询指定日期段内过生日的人员.sql
  1. SQL code
  2. --测试数据
  3. DECLARE @t TABLE(ID int,Name varchar(10),Birthday datetime)
  4. INSERT @t SELECT 1,'aa','1999-01-01'
  5. UNION ALL SELECT 2,'bb','1996-02-29'
  6. UNION ALL SELECT 3,'bb','1934-03-01'
  7. UNION ALL SELECT 4,'bb','1966-04-01'
  8. UNION ALL SELECT 5,'bb','1997-05-01'
  9. UNION ALL SELECT 6,'bb','1922-11-21'
  10. UNION ALL SELECT 7,'bb','1989-12-11'

  11. DECLARE @dt1 datetime,@dt2 datetime

  12. --查询 2003-12-05 至 2004-02-28 生日的记录
  13. SELECT @dt1='2003-12-05',@dt2='2004-02-28'
  14. SELECT * FROM @t
  15. WHERE DATEADD(Year,DATEDIFF(Year,Birthday,@dt1),Birthday)
  16.         BETWEEN @dt1 AND @dt2
  17.     OR DATEADD(Year,DATEDIFF(Year,Birthday,@dt2),Birthday)
  18.         BETWEEN @dt1 AND @dt2
  19. /*--结果
  20. ID         Name       Birthday
  21. ---------------- ---------------- --------------------------
  22. 1           aa         1999-01-01 00:00:00.000
  23. 7           bb         1989-12-11 00:00:00.000
  24. --*/

  25. --查询 2003-12-05 至 2006-02-28 生日的记录
  26. SET @dt2='2006-02-28'
  27. SELECT * FROM @t
  28. WHERE DATEADD(Year,DATEDIFF(Year,Birthday,@dt1),Birthday)
  29.         BETWEEN @dt1 AND @dt2
  30.     OR DATEADD(Year,DATEDIFF(Year,Birthday,@dt2),Birthday)
  31.         BETWEEN @dt1 AND @dt2
  32. /*--查询结果
  33. ID         Name       Birthday
  34. ---------------- ----------------- --------------------------
  35. 1           aa         1999-01-01 00:00:00.000
  36. 2           bb         1996-02-29 00:00:00.000
  37. 7           bb         1989-12-11 00:00:00.000
  38. --*/



复制代码
9.生成日期列表的函数.sql
  1. SQL code
  2. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_getdate]') and xtype in (N'FN', N'IF', N'TF'))
  3. drop function [dbo].[f_getdate]
  4. GO

  5. /*--生成日期列表
  6.    
  7.     生成指定年份的工作日/休息日列表

  8. --邹建 2003.12(引用请保留此信息)--*/

  9. /*--调用示例

  10.     --查询 2003 年的工作日列表
  11.     SELECT * FROM dbo.f_getdate(2003,0)
  12.    
  13.     --查询 2003 年的休息日列表
  14.     SELECT * FROM dbo.f_getdate(2003,1)

  15.     --查询 2003 年全部日期列表
  16.     SELECT * FROM dbo.f_getdate(2003,NULL)
  17. --*/
  18. CREATE FUNCTION dbo.f_getdate(
  19. @year int,    --要查询的年份
  20. @bz bit       --@bz=0 查询工作日,@bz=1 查询休息日,@bz IS NULL 查询全部日期
  21. )RETURNS @re TABLE(id int identity(1,1),Date datetime,Weekday nvarchar(3))
  22. AS
  23. BEGIN
  24.     DECLARE @tb TABLE(ID int IDENTITY(0,1),Date datetime)
  25.     INSERT INTO @tb(Date) SELECT TOP 366 DATEADD(Year,@YEAR-1900,'1900-1-1')
  26.     FROM sysobjects a ,sysobjects b
  27.     UPDATE @tb SET Date=DATEADD(DAY,id,Date)
  28.     DELETE FROM @tb WHERE Date>DATEADD(Year,@YEAR-1900,'1900-12-31')
  29.    
  30.     IF @bz=0
  31.         INSERT INTO @re(Date,Weekday)
  32.         SELECT Date,DATENAME(Weekday,Date)
  33.         FROM @tb
  34.         WHERE (DATEPART(Weekday,Date)+@@DATEFIRST-1)%7 BETWEEN 1 AND 5
  35.     ELSE IF @bz=1
  36.         INSERT INTO @re(Date,Weekday)
  37.         SELECT Date,DATENAME(Weekday,Date)
  38.         FROM @tb
  39.         WHERE (DATEPART(Weekday,Date)+@@DATEFIRST-1)%7 IN (0,6)
  40.     ELSE
  41.         INSERT INTO @re(Date,Weekday)
  42.         SELECT Date,DATENAME(Weekday,Date)
  43.         FROM @tb
  44.         
  45.     RETURN
  46. END
  47. GO


  48. /*====================================================================*/

  49. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_getdate]') and xtype in (N'FN', N'IF', N'TF'))
  50. drop function [dbo].[f_getdate]
  51. GO

  52. /*--生成列表

  53.     生成指定日期段的日期列表

  54. --邹建 2005.03(引用请保留此信息)--*/

  55. /*--调用示例

  56.     --查询工作日
  57.     SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',0)
  58.    
  59.     --查询休息日
  60.     SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',1)
  61.    
  62.     --查询全部日期
  63.     SELECT * FROM dbo.f_getdate('2005-1-3','2005-4-5',NULL)
  64. --*/

  65. CREATE FUNCTION dbo.f_getdate(
  66. @begin_date Datetime,  --要查询的开始日期
  67. @end_date Datetime,    --要查询的结束日期
  68. @bz bit                --@bz=0 查询工作日,@bz=1 查询休息日,@bz IS NULL 查询全部日期
  69. )RETURNS @re TABLE(id int identity(1,1),Date datetime,Weekday nvarchar(3))
  70. AS
  71. BEGIN
  72.     DECLARE @tb TABLE(ID int IDENTITY(0,1),a bit)
  73.     INSERT INTO @tb(a) SELECT TOP 366 0
  74.     FROM sysobjects a ,sysobjects b
  75.    
  76.     IF @bz=0
  77.         WHILE @begin_date<=@end_date
  78.         BEGIN
  79.             INSERT INTO @re(Date,Weekday)
  80.             SELECT Date,DATENAME(Weekday,Date)
  81.             FROM(
  82.                 SELECT Date=DATEADD(Day,ID,@begin_date)
  83.                 FROM @tb               
  84.             )a WHERE Date<=@end_date
  85.                 AND (DATEPART(Weekday,Date)+@@DATEFIRST-1)%7 BETWEEN 1 AND 5
  86.             SET @begin_date=DATEADD(Day,366,@begin_date)
  87.         END
  88.     ELSE IF @bz=1
  89.         WHILE @begin_date<=@end_date
  90.         BEGIN
  91.             INSERT INTO @re(Date,Weekday)
  92.             SELECT Date,DATENAME(Weekday,Date)
  93.             FROM(
  94.                 SELECT Date=DATEADD(Day,ID,@begin_date)
  95.                 FROM @tb               
  96.             )a WHERE Date<=@end_date
  97.                 AND (DATEPART(Weekday,Date)+@@DATEFIRST-1)%7 in(0,6)
  98.             SET @begin_date=DATEADD(Day,366,@begin_date)
  99.         END
  100.     ELSE
  101.         WHILE @begin_date<=@end_date
  102.         BEGIN
  103.             INSERT INTO @re(Date,Weekday)
  104.             SELECT Date,DATENAME(Weekday,Date)
  105.             FROM(
  106.                 SELECT Date=DATEADD(Day,ID,@begin_date)
  107.                 FROM @tb               
  108.             )a WHERE Date<=@end_date
  109.             SET @begin_date=DATEADD(Day,366,@begin_date)
  110.         END

  111.     RETURN
  112. END

复制代码
4#
 楼主| 发表于 2011-11-17 23:25:23 | 只看该作者
10.复杂年月处理.sql
  1. SQL code --定义基本数字表
  2. declare @T1 table(代码 int,名称 varchar(10),参加时间 datetime,终止时间 datetime)
  3. insert into @T1
  4.     select 12,'单位1','2003/04/01','2004/05/01'
  5.     union all select 22,'单位2','2001/02/01','2003/02/01'
  6.     union all select 42,'单位3','2000/04/01','2003/05/01'
  7.     union all select 25,'单位5','2003/04/01','2003/05/01'

  8. --定义年表
  9. declare @NB table(代码 int,名称 varchar(10),年份 int)
  10. insert into @NB
  11.     select 12,'单位1',2003
  12.     union all select 12,'单位1',2004
  13.     union all select 22,'单位2',2001
  14.     union all select 22,'单位2',2002
  15.     union all select 22,'单位2',2003

  16. --定义月表
  17. declare @YB table(代码 int,名称 varchar(10),年份 int,月份 varchar(2))
  18. insert into @YB
  19.     select 12,'单位1',2003,'04'
  20.     union all select 22,'单位2',2001,'01'
  21.     union all select 22,'单位2',2001,'12'

  22. --为年表+月表数据处理准备临时表
  23. select top 8246 y=identity(int,1753,1)
  24. into #tby from
  25.     (select id from syscolumns) a,
  26.     (select id from syscolumns) b,
  27.     (select id from syscolumns) c

  28. --为月表数据处理准备临时表
  29. select top 12 m=identity(int,1,1)
  30. into #tbm from syscolumns

  31. /*--数据处理--*/
  32. --年表数据处理
  33. select a.*
  34. from(
  35. select a.代码,a.名称,年份=b.y
  36. from @T1 a,#tby b
  37. where b.y between year(参加时间) and year(终止时间)
  38. ) a left join @NB b on a.代码=b.代码 and a.年份=b.年份
  39. where b.代码 is null

  40. --月表数据处理
  41. select a.*
  42. from(
  43. select a.代码,a.名称,年份=b.y,月份=right('00'+cast(c.m as varchar),2)
  44. from @T1 a,#tby b,#tbm c
  45. where b.y*100+c.m between convert(varchar(6),参加时间,112)
  46.     and convert(varchar(6),终止时间,112)
  47. ) a left join @YB b on a.代码=b.代码 and a.年份=b.年份 and a.月份=b.月份
  48. where b.代码 is null
  49. order by a.代码,a.名称,a.年份,a.月份

  50. --删除数据处理临时表
  51. drop table #tby,#tbm
复制代码
11.交叉表.sql
  1. SQL code --示例

  2. --示例数据
  3. create table tb(ID int,Time datetime)
  4. insert tb select 1,'2005/01/24 16:20'
  5. union all select 2,'2005/01/23 22:45'
  6. union all select 3,'2005/01/23 0:30'
  7. union all select 4,'2005/01/21 4:28'
  8. union all select 5,'2005/01/20 13:22'
  9. union all select 6,'2005/01/19 20:30'
  10. union all select 7,'2005/01/19 18:23'
  11. union all select 8,'2005/01/18 9:14'
  12. union all select 9,'2005/01/18 18:04'
  13. go

  14. --查询处理:
  15. select     case when grouping(b.Time)=1 then 'Total' else b.Time end,
  16.     [Mon]=sum(case a.week when 1 then 1 else 0 end),
  17.     [Tue]=sum(case a.week when 2 then 1 else 0 end),
  18.     [Wed]=sum(case a.week when 3 then 1 else 0 end),
  19.     [Thu]=sum(case a.week when 4 then 1 else 0 end),
  20.     [Fri]=sum(case a.week when 5 then 1 else 0 end),
  21.     [Sat]=sum(case a.week when 6 then 1 else 0 end),
  22.     [Sun]=sum(case a.week when 0 then 1 else 0 end),
  23.     [Total]=count(a.week)
  24. from(
  25.     select Time=convert(char(5),dateadd(hour,-1,Time),108)
  26.             --时间交界点是1am,所以减1小时,避免进行跨天处理
  27.         ,week=(@@datefirst+datepart(weekday,Time)-1)%7
  28.             --考虑@@datefirst对datepart的影响
  29.     from tb
  30. )a right join(
  31.     select id=1,a='16:00',b='19:59',Time='[5pm - 9pm)' union all
  32.     select id=2,a='20:00',b='23:59',Time='[9pm - 1am)' union all
  33.     select id=3,a='00:00',b='02:59',Time='[1am - 4am)' union all
  34.     select id=4,a='03:00',b='07:29',Time='[4am - 8:30am)' union all
  35.     select id=5,a='07:30',b='11:59',Time='[8:30am - 1pm)' union all
  36.     select id=6,a='12:00',b='15:59',Time='[1pm - 5pm)'
  37. )b on a.Time>=b.a and a.Time<b.b
  38. group by b.id,b.Time with rollup
  39. having grouping(b.Time)=0 or grouping(b.id)=1
  40. go

  41. --删除测试
  42. drop table tb

  43. /*--测试结果

  44.                Mon   Tue   Wed   Thu   Fri   Sat   Sun   Total
  45. -------------- ----- ----- ----- ----- ----- ------ ---- -------
  46. [5pm - 9pm)    0     1     2     0     0     0     0     3
  47. [9pm - 1am)    0     0     0     0     0     0     2     2
  48. [1am - 4am)    0     0     0     0     0     0     0     0
  49. [4am - 8:30am) 0     0     0     0     1     0     0     1
  50. [8:30am - 1pm) 0     1     0     0     0     0     0     1
  51. [1pm - 5pm)    1     0     0     1     0     0     0     2
  52. Total          1     2     2     1     1     0     2     9

  53. (所影响的行数为 7 行)
  54. --*/
复制代码
12.任意两个时间之间的星期几的次数-横.sql
  1. 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'))
  2. drop function [dbo].[f_weekdaycount]
  3. GO

  4. /*--计算任意两个时间之间的星期几的次数(横向显示)

  5.     本方法直接判断 @@datefirst 做对应处理
  6.     不受 sp_language 及 set datefirst 的影响     

  7. --邹建 2004.08(引用请保留此信息)--*/

  8. /*--调用示例
  9.    
  10.     select * from f_weekdaycount('2004-9-01','2004-9-02')
  11. --*/
  12. create function f_weekdaycount(
  13. @dt_begin datetime,
  14. @dt_end datetime
  15. )returns table
  16. as
  17. return(
  18.     select 跨周数
  19.         ,周一=case a
  20.             when -1 then case when 1 between b and c then 1 else 0 end
  21.             when  0 then case when b<=1 then 1 else 0 end
  22.                     +case when c>=1 then 1 else 0 end
  23.             else a+case when b<=1 then 1 else 0 end
  24.                 +case when c>=1 then 1 else 0 end
  25.             end
  26.         ,周二=case a
  27.             when -1 then case when 2 between b and c then 1 else 0 end
  28.             when  0 then case when b<=2 then 1 else 0 end
  29.                     +case when c>=2 then 1 else 0 end
  30.             else a+case when b<=2 then 1 else 0 end
  31.                 +case when c>=2 then 1 else 0 end
  32.             end
  33.         ,周三=case a
  34.             when -1 then case when 3 between b and c then 1 else 0 end
  35.             when  0 then case when b<=3 then 1 else 0 end
  36.                     +case when c>=3 then 1 else 0 end
  37.             else a+case when b<=3 then 1 else 0 end
  38.                 +case when c>=3 then 1 else 0 end
  39.             end
  40.         ,周四=case a
  41.             when -1 then case when 4 between b and c then 1 else 0 end
  42.             when  0 then case when b<=4 then 1 else 0 end
  43.                     +case when c>=4 then 1 else 0 end
  44.             else a+case when b<=4 then 1 else 0 end
  45.                 +case when c>=4 then 1 else 0 end
  46.             end
  47.         ,周五=case a
  48.             when -1 then case when 5 between b and c then 1 else 0 end
  49.             when  0 then case when b<=5 then 1 else 0 end
  50.                     +case when c>=5 then 1 else 0 end
  51.             else a+case when b<=5 then 1 else 0 end
  52.                 +case when c>=5 then 1 else 0 end
  53.             end
  54.         ,周六=case a
  55.             when -1 then case when 6 between b and c then 1 else 0 end
  56.             when  0 then case when b<=6 then 1 else 0 end
  57.                     +case when c>=6 then 1 else 0 end
  58.             else a+case when b<=6 then 1 else 0 end
  59.                 +case when c>=6 then 1 else 0 end
  60.             end
  61.         ,周日=case a
  62.             when -1 then case when 0 between b and c then 1 else 0 end
  63.             when  0 then case when b<=0 then 1 else 0 end
  64.                     +case when c>=0 then 1 else 0 end
  65.             else a+case when b<=0 then 1 else 0 end
  66.                 +case when c>=0 then 1 else 0 end
  67.             end
  68.     from(
  69.         select 跨周数=case when @dt_begin<@dt_end
  70.                 then (datediff(day,@dt_begin,@dt_end)+7)/7
  71.                 else (datediff(day,@dt_end,@dt_begin)+7)/7 end
  72.             ,a=case when @dt_begin<@dt_end
  73.                 then datediff(week,@dt_begin,@dt_end)-1
  74.                 else datediff(week,@dt_end,@dt_begin)-1 end
  75.             ,b=case when @dt_begin<@dt_end
  76.                 then (@@datefirst+datepart(weekday,@dt_begin)-1)%7
  77.                 else (@@datefirst+datepart(weekday,@dt_end)-1)%7 end
  78.             ,c=case when @dt_begin<@dt_end
  79.                 then (@@datefirst+datepart(weekday,@dt_end)-1)%7
  80.                 else (@@datefirst+datepart(weekday,@dt_begin)-1)%7 end)a
  81. )
  82. go

复制代码
5#
 楼主| 发表于 2011-11-17 23:28:41 | 只看该作者
13.统计--交叉表+日期+优先.sql
  1. SQL code --交叉表,根据优先级取数据,日期处理

  2. 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)
  3. insert tb select 1,'A1','未订','08:00','09:00',1   ,5   ,null       ,null       ,1
  4. union all select 1,'A1','未订','09:00','10:00',1   ,5   ,null       ,null       ,1
  5. union all select 1,'A1','未订','10:00','11:00',1   ,5   ,null       ,null       ,1
  6. union all select 1,'A1','装修','08:00','09:00',null,null,'2005-1-18','2005-1-19',2
  7. --union all select 1,'A1','装修','09:00','10:00',null,null,'2005-1-18','2005-1-19',2
  8. union all select 1,'A1','装修','10:00','11:00',null,null,'2005-1-18','2005-1-19',2
  9. union all select 1,'A2','未订','08:00','09:00',1   ,5   ,null       ,null       ,1
  10. union all select 1,'A2','未订','09:00','10:00',1   ,5   ,null       ,null       ,1
  11. union all select 1,'A2','未订','10:00','11:00',1   ,5   ,null       ,null       ,1
  12. --union all select 1,'A2','装修','08:00','09:00',null,null,'2005-1-18','2005-1-19',2
  13. union all select 1,'A2','装修','09:00','10:00',null,null,'2005-1-18','2005-1-19',2
  14. --union all select 1,'A2','装修','10:00','11:00',null,null,'2005-1-18','2005-1-19',2
  15. go

  16. /*--楼主这个问题要考虑几个方面

  17.     1. 取星期时,set datefirst 的影响
  18.     2. 优先级问题
  19.     3. qid,rid 应该是未知的(动态变化的)
  20. --*/

  21. --实现的存储过程如下
  22. create proc p_qry
  23. @date smalldatetime --要查询的日期
  24. as
  25. set nocount on
  26. declare @week int,@s nvarchar(4000)
  27. --格式化日期和得到星期
  28. select @date=convert(char(10),@date,120)
  29.     ,@week=(@@datefirst+datepart(weekday,@date)-1)%7
  30.     ,@s=''
  31. select id=identity(int),* into #t
  32. from(
  33.     select top 100 percent
  34.         qid,rid,tagname,
  35.         starttime=convert(char(5),starttime,108),
  36.         endtime=convert(char(5),endtime,108)
  37.     from tb
  38.     where (@week between startweekday and endweekday)
  39.         or(@date between startdate and enddate)
  40.     order by qid,rid,starttime,d desc)a

  41. select @s=@s+N',['+rtrim(rid)
  42.     +N']=max(case when qid='+rtrim(qid)
  43.     +N' and rid=N'''+rtrim(rid)
  44.     +N''' then tagname else N'''' end)'
  45. from #t group by qid,rid
  46. exec('
  47. select starttime,endtime'+@s+'
  48. from #t a
  49. where not exists(
  50.     select * from #t
  51.     where qid=a.qid and rid=a.rid
  52.         and starttime=a.starttime
  53.         and endtime=a.endtime
  54.         and id<a.id)
  55. group by starttime,endtime')
  56. go

  57. --调用
  58. exec p_qry '2005-1-17'
  59. exec p_qry '2005-1-18'
  60. go

  61. --删除测试
  62. drop table tb
  63. drop proc p_qry

  64. /*--测试结果

  65. starttime endtime A1         A2         
  66. --------- ------- ---------- ----------
  67. 08:00     09:00   未订         未订
  68. 09:00     10:00   未订         未订
  69. 10:00     11:00   未订         未订

  70. starttime endtime A1         A2         
  71. --------- ------- ---------- ----------
  72. 08:00     09:00   装修         未订
  73. 09:00     10:00   未订         装修
  74. 10:00     11:00   装修         未订
  75. --*/
复制代码
14.工作日处理函数(标准节假日).sql
  1. 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'))
  2. drop function [dbo].[f_WorkDay]
  3. GO

  4. --计算两个日期相差的工作天数
  5. CREATE FUNCTION f_WorkDay(
  6. @dt_begin datetime,  --计算的开始日期
  7. @dt_end  datetime    --计算的结束日期
  8. )RETURNS int
  9. AS
  10. BEGIN
  11.     DECLARE @workday int,@i int,@bz bit,@dt datetime
  12.     IF @dt_begin>@dt_end
  13.         SELECT @bz=1,@dt=@dt_begin,@dt_begin=@dt_end,@dt_end=@dt
  14.     ELSE
  15.         SET @bz=0
  16.     SELECT @i=DATEDIFF(Day,@dt_begin,@dt_end)+1,
  17.         @workday=@i/7*5,
  18.         @dt_begin=DATEADD(Day,@i/7*7,@dt_begin)
  19.     WHILE @dt_begin<=@dt_end
  20.     BEGIN
  21.         SELECT @workday=CASE
  22.             WHEN (@@DATEFIRST+DATEPART(Weekday,@dt_begin)-1)%7 BETWEEN 1 AND 5
  23.             THEN @workday+1 ELSE @workday END,
  24.             @dt_begin=@dt_begin+1
  25.     END
  26.     RETURN(CASE WHEN @bz=1 THEN -@workday ELSE @workday END)
  27. END
  28. GO



  29. /*=================================================================*/

  30. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDayADD]') and xtype in (N'FN', N'IF', N'TF'))
  31. drop function [dbo].[f_WorkDayADD]
  32. GO

  33. --在指定日期上,增加指定工作天数后的日期
  34. CREATE FUNCTION f_WorkDayADD(
  35. @date    datetime,  --基础日期
  36. @workday int       --要增加的工作日数
  37. )RETURNS datetime
  38. AS
  39. BEGIN
  40.     DECLARE @bz int
  41.     --增加整周的天数
  42.     SELECT @bz=CASE WHEN @workday<0 THEN -1 ELSE 1 END
  43.         ,@date=DATEADD(Week,@workday/5,@date)
  44.         ,@workday=@workday%5
  45.     --增加不是整周的工作天数
  46.     WHILE @workday<>0
  47.         SELECT @date=DATEADD(Day,@bz,@date),
  48.             @workday=CASE WHEN (@@DATEFIRST+DATEPART(Weekday,@date)-1)%7 BETWEEN 1 AND 5
  49.                 THEN @workday-@bz ELSE @workday END
  50.     --避免处理后的日期停留在非工作日上
  51.     WHILE (@@DATEFIRST+DATEPART(Weekday,@date)-1)%7 in(0,6)
  52.         SET @date=DATEADD(Day,@bz,@date)
  53.     RETURN(@date)
  54. END



复制代码
15.工作日处理函数(自定义节假日).sql
  1. SQL code if exists (select * from dbo.sysobjects where id = object_id(N'[tb_Holiday]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
  2. drop table [tb_Holiday]
  3. GO

  4. --定义节假日表
  5. CREATE TABLE tb_Holiday(
  6. HDate smalldatetime primary key clustered, --节假日期
  7. Name nvarchar(50) not null)             --假日名称
  8. GO

  9. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDay]') and xtype in (N'FN', N'IF', N'TF'))
  10. drop function [dbo].[f_WorkDay]
  11. GO

  12. --计算两个日期之间的工作天数
  13. CREATE FUNCTION f_WorkDay(
  14. @dt_begin datetime,  --计算的开始日期
  15. @dt_end  datetime   --计算的结束日期
  16. )RETURNS int
  17. AS
  18. BEGIN
  19.     IF @dt_begin>@dt_end
  20.         RETURN(DATEDIFF(Day,@dt_begin,@dt_end)
  21.             +1-(
  22.                 SELECT COUNT(*) FROM tb_Holiday
  23.                 WHERE HDate BETWEEN @dt_begin AND @dt_end))
  24.     RETURN(-(DATEDIFF(Day,@dt_end,@dt_begin)
  25.         +1-(
  26.             SELECT COUNT(*) FROM tb_Holiday
  27.             WHERE HDate BETWEEN @dt_end AND @dt_begin)))
  28. END
  29. GO

  30. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDayADD]') and xtype in (N'FN', N'IF', N'TF'))
  31. drop function [dbo].[f_WorkDayADD]
  32. GO

  33. --在指定日期上增加工作天数
  34. CREATE FUNCTION f_WorkDayADD(
  35. @date    datetime,  --基础日期
  36. @workday int       --要增加的工作日数
  37. )RETURNS datetime
  38. AS
  39. BEGIN
  40.     IF @workday>0
  41.         WHILE @workday>0
  42.             SELECT @date=@date+@workday,@workday=count(*)
  43.             FROM tb_Holiday
  44.             WHERE HDate BETWEEN @date AND @date+@workday
  45.     ELSE
  46.         WHILE @workday<0
  47.             SELECT @date=@date+@workday,@workday=-count(*)
  48.             FROM tb_Holiday
  49.             WHERE HDate BETWEEN @date AND @date+@workday
  50.     RETURN(@date)
  51. END

复制代码
6#
 楼主| 发表于 2011-11-17 23:30:02 | 只看该作者
16.计算工作时间的函数.sql
  1. SQL code if exists (select * from dbo.sysobjects where id = object_id(N'[tb_worktime]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
  2. drop table [tb_worktime]
  3. GO

  4. --定义工作时间表
  5. CREATE TABLE tb_worktime(
  6.     ID       int identity(1,1) PRIMARY KEY,            --序号
  7.     time_start smalldatetime,                            --工作的开始时间
  8.     time_end  smalldatetime,                           --工作的结束时间
  9.     worktime  AS DATEDIFF(Minute,time_start,time_end)  --工作时数(分钟)
  10. )
  11. GO

  12. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkTime]') and xtype in (N'FN', N'IF', N'TF'))
  13. drop function [dbo].[f_WorkTime]
  14. GO

  15. --计算两个日期之间的工作时间
  16. CREATE FUNCTION f_WorkTime(
  17. @date_begin datetime,  --计算的开始时间
  18. @date_end datetime     --计算的结束时间
  19. )RETURNS int
  20. AS
  21. BEGIN
  22.     DECLARE @worktime int
  23.     IF DATEDIFF(Day,@date_begin,@date_end)=0
  24.         SELECT @worktime=SUM(DATEDIFF(Minute,
  25.             CASE WHEN CONVERT(VARCHAR,@date_begin,108)>time_start
  26.                 THEN CONVERT(VARCHAR,@date_begin,108)
  27.                 ELSE time_start END,
  28.             CASE WHEN CONVERT(VARCHAR,@date_end,108)<time_end
  29.                 THEN CONVERT(VARCHAR,@date_end,108)
  30.                 ELSE time_end END))
  31.         FROM tb_worktime
  32.         WHERE time_end>CONVERT(VARCHAR,@date_begin,108)
  33.             AND time_start<CONVERT(VARCHAR,@date_end,108)
  34.     ELSE
  35.         SET @worktime
  36.             =(SELECT SUM(CASE
  37.                     WHEN CONVERT(VARCHAR,@date_begin,108)>time_start
  38.                     THEN DATEDIFF(Minute,CONVERT(VARCHAR,@date_begin,108),time_end)
  39.                     ELSE worktime END)
  40.                 FROM tb_worktime
  41.                 WHERE time_end>CONVERT(VARCHAR,@date_begin,108))
  42.             +(SELECT SUM(CASE
  43.                     WHEN CONVERT(VARCHAR,@date_end,108)<time_end
  44.                     THEN DATEDIFF(Minute,time_start,CONVERT(VARCHAR,@date_end,108))
  45.                     ELSE worktime END)
  46.                 FROM tb_worktime
  47.                 WHERE time_start<CONVERT(VARCHAR,@date_end,108))
  48.             +CASE
  49.                 WHEN DATEDIFF(Day,@date_begin,@date_end)>1
  50.                 THEN (DATEDIFF(Day,@date_begin,@date_end)-1)
  51.                     *(SELECT SUM(worktime) FROM tb_worktime)
  52.                 ELSE 0 END
  53.     RETURN(@worktime)
  54. END

复制代码

点击这里给我发消息

7#
发表于 2011-11-18 21:16:46 | 只看该作者
赞一个!
8#
发表于 2011-11-22 14:54:31 | 只看该作者
哗.好东西.
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|站长邮箱|小黑屋|手机版|Office中国/Access中国 ( 粤ICP备10043721号-1 )  

GMT+8, 2024-4-29 20:11 , Processed in 0.114978 second(s), 31 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表