看到网上有高手直接用sql查询创建日历,也想自己动手实践一遍。笔者这里的实现和网上的都没有什么区别,思路也没有什么新意。觉得好玩,就把它记下来吧。 
一、准备知识
1、sql的with关键字
关于with和公用表表达式(CTE),可以参考SQL Server 2005新特性之使用with关键字解决递归父子关系
Sql Server2005 Transact-SQL 新兵器学习总结之-公用表表达式(CTE) 。
2、sql的pivot关键字
pivot非常强大,但是对于新手来说,可能连这个单词都很生僻,使用也是举步维艰。pivot的示例可以参考这篇这篇
二、实现
1、实现思路:
使用递归with子句,返回当前月的每一天,然后使用case和max转换为周内日期。
2、辅助表T1


USE [TestDb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[T1](
    [tid] [int] NOT NULL,
 CONSTRAINT [PK_T1] PRIMARY KEY CLUSTERED 
(
    [tid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

说明:T1表中有且只有一条记录:insert into t1 values(1)
3、生成日历的sql


with x(dy,dm,mth,dw,wk)
as(
select dy,day(dy) dm,datepart(m,dy) mth,datepart(dw,dy) dw,
case when datepart(dw,dy)=1
then datepart(ww,dy)-1
else datepart(ww,dy) end wk
from ( select dateadd(day,-day(getdate())+1,getdate()) dy from t1) x
union all select dateadd(d,1,dy),day(dateadd(d,1,dy)),mth,
datepart(dw,dateadd(d,1,dy)),
case when datepart(dw,dateadd(d,1,dy))=1
then datepart(wk,dateadd(d,1,dy))-1
else datepart(wk,dateadd(d,1,dy)) end
from x where datepart(m,dateadd(d,1,dy))=mth)
select max(case dw when 2 then dm end) as '星期一',
       max(case dw when 3 then dm end) as '星期二',
       max(case dw when 4 then dm end) as '星期三',
       max(case dw when 5 then dm end) as '星期四',
       max(case dw when 6 then dm end) as '星期五',
       max(case dw when 7 then dm end) as '星期六',
       max(case dw when 1 then dm end) as '星期日'
from x group by wk order by wk

图片:
4、生成日历sql语句说明
(1)首先,为当前月的每一天返回一行信息。可以使用sql server支持递归with的with子句来实现。返回的每一行包含的信息:月份日期(dm),星期几(dw),当前月份(mth),iso周序号(wk)。
(2)在递归之前,递归视图x产生的结果(union all的上半部分)如下所示:

select dy,day(dy) dm,datepart(m,dy) mth,datepart(dw,dy) dw,
case when datepart(dw,dy)=1
then datepart(ww,dy)-1
else datepart(ww,dy) end wk
from ( select dateadd(day,-day(getdate())+1,getdate()) dy from t1) x

(3)下一步重复递增dm值(递增次数就是月份对应天数),直到超出当前月为止。在对当前月的每一天进行处理时,也会得到每天对应星期几以及当日的iso周序号。


with x(dy,dm,mth,dw,wk)
as(
select dy,day(dy) dm,datepart(m,dy) mth,datepart(dw,dy) dw,
case when datepart(dw,dy)=1
then datepart(ww,dy)-1
else datepart(ww,dy) end wk
from ( select dateadd(day,-day(getdate())+1,getdate()) dy from t1) x
union all select dateadd(d,1,dy),day(dateadd(d,1,dy)),mth,
datepart(dw,dateadd(d,1,dy)),
case when datepart(dw,dateadd(d,1,dy))=1
then datepart(wk,dateadd(d,1,dy))-1
else datepart(wk,dateadd(d,1,dy)) end
from x where datepart(m,dateadd(d,1,dy))=mth)
select *
from x 

此时,当前月的每一天包含的信息有:月份日期值,月份值,一位数字表示的星期几(1-7分别对应星期日到星期六)以及iso周序号。
(4)使用一个case表达式确定dm(当前月的每一天)中每个值对应星期几。


with x(dy,dm,mth,dw,wk)
as(
select dy,day(dy) dm,datepart(m,dy) mth,datepart(dw,dy) dw,
case when datepart(dw,dy)=1
then datepart(ww,dy)-1
else datepart(ww,dy) end wk
from ( select dateadd(day,-day(getdate())+1,getdate()) dy from t1) x
union all select dateadd(d,1,dy),day(dateadd(d,1,dy)),mth,
datepart(dw,dateadd(d,1,dy)),
case when datepart(dw,dateadd(d,1,dy))=1
then datepart(wk,dateadd(d,1,dy))-1
else datepart(wk,dateadd(d,1,dy)) end
from x where datepart(m,dateadd(d,1,dy))=mth)
select case dw when 2 then dm end as '星期一',
       case dw when 3 then dm end as '星期二',
       case dw when 4 then dm end as '星期三',
       case dw when 5 then dm end as '星期四',
       case dw when 6 then dm end as '星期五',
       case dw when 7 then dm end as '星期六',
       case dw when 1 then dm end as '星期日'
from x 

这里每周的每一天都独占一行,在每行中,包含日期编号的列都与星期名相对应。
(5)最后把每周的所有日期放在一行中
正如本文3中给出的最终sql语句一样,对各列使用聚集函数max,并且按照周序号wk分组排序即可。 
ps:最终结果在sql server2005下测试通过,其他版本未测试。 不过sql server 2005版本下利用dbms自带的函数pivot可以很轻松实现日历的:


Use testdb
go Declare 
    @Date datetime,
    @StartDate datetime,
    @EndDate datetime,
    @FirstIndex int Set @Date =getdate() --输入一个日期,即可算出当月的日历 比如输入20080808,这里取当前日期 Select 
    @StartDate=Convert(char(6),@Date,112)+'01', 
    @EndDate=Dateadd(month,1,@StartDate)-1,
    @FirstIndex=Datediff(day,0,@StartDate)%7 ;
With t As
(
    Select Date=Convert(int,1),Row=(@FirstIndex)/7,Col=@FirstIndex
    Union All
    Select Date=Date+1,Row=(@FirstIndex+Date)/7,Col=(Date+@FirstIndex)%7
    From t
    Where Date<=Datediff(day,@StartDate,@EndDate)
)
Select 
    [星期一]=Isnull(Convert(char(2),[0]),''),
    [星期二]=Isnull(Convert(char(2),[1]),''),
    [星期三]=Isnull(Convert(char(2),[2]),''),
    [星期四]=Isnull(Convert(char(2),[3]),''),
    [星期五]=Isnull(Convert(char(2),[4]),''),
    [星期六]=Isnull(Convert(char(2),[5]),''),
    [星期日]=Isnull(Convert(char(2),[6]),'')
From t
Pivot (Max(Date) For col In([0],[1],[2],[3],[4],[5],[6])) b

pivot真是华丽的强大,强大的华丽啊。

利用sql server直接创建日历的更多相关文章

  1. 利用SQL Server 2008 R2创建自动备份计划

    本文主要利用SQL Server 2008 R2自带的"维护计划"创建一个自动备份数据的任务. 首先,启动 Sql Management studio,确保"SQL Se ...

  2. 四、利用SQL Server 2008 R2创建自动备份计划

    (转) 本文主要利用SQL Server 2008 R2自带的"维护计划"创建一个自动备份数据的任务. 首先,启动 Sql Management studio,确保"SQ ...

  3. ASP.net(C#)利用SQL Server实现注册和登陆功能

    说说我现在吧,楼主现在从事的事IT行业,主攻DotNet技术:当然这次上博客园我也是有备而来,所有再次奉献鄙人拙作,以飨诸位,望诸位不吝赐教. 世界上大多数的工作都是熟练性的工种,编程也不例外,做久了 ...

  4. 在64位SQL Server中创建Oracle的链接服务器

    当我们同时使用SQL Server和Oracle来存储数据时,经常会用到跨库查询.为了方便使用跨库查询,一个最好的办法就是通过创建链接服务器来实现.既可以在SQL Server中创建Oracle的链接 ...

  5. sql server 脚本创建数据库邮件

    sql server 脚本创建数据库邮件代码: --脚本创建数据库邮件 --1.开启数据库邮件 RECONFIGURE WITH OVERRIDE GO RECONFIGURE WITH OVERRI ...

  6. sql server中创建链接服务器图解教程

    转自sql server中创建链接服务器图解教程 1.展开服务器对象-->链接服务器-->右击"新建链接服务器" 注意:必须以数据库管理员身份登录(通常也就是sa帐号) ...

  7. sql server 数据库创建链接服务器访问另外一个sql server 数据库

    继上篇在sql server中创建链接服务器访问oracle数据库:http://www.cnblogs.com/527289276qq/p/4770379.html 本文介绍在sql server中 ...

  8. sql server 数据库创建链接服务器

    本文介绍在sql server中创建链接服务器访问sql server数据库. 方法: 打开SSMS,新建程序,执行下面sql语句块: EXEC sp_addlinkedserver @server= ...

  9. 在64位SQL Server中创建Oracle的链接服务器 Link Server

    有时候我们希望在一个sqlserver下访问另一个sqlserver数据库上的数据,或者访问其他oracle数据库上的数据,要想完成这些操作,我们首要的是创建数据库链接. 数据库链接能够让本地的一个s ...

随机推荐

  1. PHP正则表达式函数学习

    正则表达式是在日常开发中经常用到的,通常一些使用频率过高的正则表达式都是直接粘贴复制,对于基础正则的使用还是要铭记于心的,今天抽时间整理一些php正则表达式的用法. 一.php中常用的正则表达式函数 ...

  2. for,while,do while

    long i; ;i<;i++) printf( printf("%ld\n",i); ) printf("b\n"); i=; do { printf( ...

  3. 布谷鸟搜索算法CS

    0 引言 布谷鸟搜索(Cuckoo Search,CS)是由 Xin-She Yang 和 Suash Deb 于 2009 年开发的自然启发式算法.CS 基于布谷鸟的寄生性育雏(brood para ...

  4. Git4:Git标签

    目录 简介 新建标签 查看标签详细信息 切换标签 后期添加标签 将标签推送到远端仓库 简介 Git可以对某一时间点上的版本打上标签.人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做.本 ...

  5. Hadoop基础-Protocol Buffers串行化与反串行化

    Hadoop基础-Protocol Buffers串行化与反串行化 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们之前学习过很多种序列化文件格式,比如python中的pickl ...

  6. M-JPEG、MPEG4、H.264都有何区别

    压缩方式是网络视频服务器和网络摄像机的核心技术,压缩方式很大程度上决定着图像的质量.压缩比.传输效率.传输速度等性能,它是评价网络视频服务器和网络摄像机性能优劣的重要一环.随着多媒体技术的发展,相继推 ...

  7. centos7.2云主机安装桌面

    yum groups install "X Window System" yum groupinstall "GNOME Desktop" systemctl  ...

  8. Java时间格式转换工具类

    把当前时间修改成指定时间 //把当前时间修改成指定时间 public String dateUtil(Integer seconds, String dateFormatPattern){ Date ...

  9. 遇到can not resolve app 依赖包的问题

    1.第一种解决方式:build->sdkmannger->sdk tool ->安装android support responsitory和google responsitory ...

  10. #import 指令

    [#import 指令] #import指令用于从一个类型库中结合信息.该类型库的内容被转换为C++类,主要用于描述COM界面. 语法 #import "文件名" [属性] #im ...