利用sql server直接创建日历
看到网上有高手直接用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直接创建日历的更多相关文章
- 利用SQL Server 2008 R2创建自动备份计划
本文主要利用SQL Server 2008 R2自带的"维护计划"创建一个自动备份数据的任务. 首先,启动 Sql Management studio,确保"SQL Se ...
- 四、利用SQL Server 2008 R2创建自动备份计划
(转) 本文主要利用SQL Server 2008 R2自带的"维护计划"创建一个自动备份数据的任务. 首先,启动 Sql Management studio,确保"SQ ...
- ASP.net(C#)利用SQL Server实现注册和登陆功能
说说我现在吧,楼主现在从事的事IT行业,主攻DotNet技术:当然这次上博客园我也是有备而来,所有再次奉献鄙人拙作,以飨诸位,望诸位不吝赐教. 世界上大多数的工作都是熟练性的工种,编程也不例外,做久了 ...
- 在64位SQL Server中创建Oracle的链接服务器
当我们同时使用SQL Server和Oracle来存储数据时,经常会用到跨库查询.为了方便使用跨库查询,一个最好的办法就是通过创建链接服务器来实现.既可以在SQL Server中创建Oracle的链接 ...
- sql server 脚本创建数据库邮件
sql server 脚本创建数据库邮件代码: --脚本创建数据库邮件 --1.开启数据库邮件 RECONFIGURE WITH OVERRIDE GO RECONFIGURE WITH OVERRI ...
- sql server中创建链接服务器图解教程
转自sql server中创建链接服务器图解教程 1.展开服务器对象-->链接服务器-->右击"新建链接服务器" 注意:必须以数据库管理员身份登录(通常也就是sa帐号) ...
- sql server 数据库创建链接服务器访问另外一个sql server 数据库
继上篇在sql server中创建链接服务器访问oracle数据库:http://www.cnblogs.com/527289276qq/p/4770379.html 本文介绍在sql server中 ...
- sql server 数据库创建链接服务器
本文介绍在sql server中创建链接服务器访问sql server数据库. 方法: 打开SSMS,新建程序,执行下面sql语句块: EXEC sp_addlinkedserver @server= ...
- 在64位SQL Server中创建Oracle的链接服务器 Link Server
有时候我们希望在一个sqlserver下访问另一个sqlserver数据库上的数据,或者访问其他oracle数据库上的数据,要想完成这些操作,我们首要的是创建数据库链接. 数据库链接能够让本地的一个s ...
随机推荐
- jsp中的js中获取项目路径的方法
在jsp中加上 <% String path = request.getContextPath(); String basePath = request.getScheme()+":/ ...
- sql 事务的四种隔离级别
在 SQL 标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的.较低级别的隔离通常可以执行更高的并发,系统的开销也更低. read unco ...
- 什么是Docker并且它为什么这么受欢迎
什么是Docker (why it's so hot than hot) Docker是一个使用容器来方便快捷的创建,部署,运行程序的工具,容器允许开发人员将应用程序的一切打包(镜像),例如库和其他的 ...
- python3中SSLError错误处理
在deepin中安装了python3.6,安装路径为/usr/local/python36,然后通过deepin自带的python2.7的pip安装了virtualenv: sudo pip inst ...
- Java泛型底层源码解析--ConcurrentHashMap(JDK1.7)
1. Concurrent相关历史 JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全 ...
- [Linux]-Linux常用命令之文件解压
不压缩方式压缩的文件需要不同的命令来解压缩,下面是Linux的各种文件解压命令. 对于.tar结尾的文件: tar -xf 对于.gz结尾的文件 : gzip -d all.gz gunzip all ...
- 发现IE 9的一个独有的小bug,并附解决方案
在最近的项目中,解决了一些浏览器兼容方面的bug,这篇主要描述在IE 9在渲染值为auto的overflow-x属性时,所产生的专属bug及解决办法. 1.问题描述 在做一个收货地址管理静态页面的时候 ...
- 创建分区swap分区
1.将文件系统卸载 #umount /sdc5 2.创建swap分区 #mkswap /dev/sdc5 3.激活swap分区 #swapon -a /dev/sdc5 4.查看swap分区情况 #s ...
- 14、BigInteger类简介
BigInteger类概述 BigInteger类可以让超过Integer范围的数据进行运算,通常在对数字计算比较大的行业中应用的多一些. package com.sutaoyu.usually_cl ...
- classList属性
1.传统方法: 在操作类名的时候,需要通过className属性添加.删除和替换类名.如下面例子: ? 1 <div class="bd user disabled"> ...