关于SQLServer2005的学习笔记——生日问题
2010-02-21 15:37
701 查看
生日问题是个看似简单逻辑上却又比较复杂的小问题
主要的逻辑难点第一个是关于闰月尾天的计算,第二个是判断本年度生日是否已过
本文给出了三种解决办法,
第一种是最常用的解决办法,即常用的 SQL 语法,不过看起来比较复杂,适合环境为 SQLServer2000 以上
第二种是采用函数的方法,把对日期的逻辑处理放到函数中,调用起来会简约一下,适合环境为 SQLServer2000 以上
第三种是采用 CTE 的方法,用 CTE 来封装判断逻辑,适合环境为 SQLServer2005 以上
-- 创建表和数据
CREATE TABLE employees
(
name VARCHAR(50),
birthday DATETIME
)
INSERT INTO employees VALUES('WBQ','1948-12-08');
INSERT INTO employees VALUES('CZH','1952-02-19');
INSERT INTO employees VALUES('LB','1963-08-30');
INSERT INTO employees VALUES('YLL','1937-09-19');
INSERT INTO employees VALUES('YGQ','1955-03-04');
INSERT INTO employees VALUES('CHH','1963-07-02');
INSERT INTO employees VALUES('SWG','1960-05-29');
INSERT INTO employees VALUES('HW','1958-01-01');
INSERT INTO employees VALUES('YY','1972-02-29');
INSERT INTO employees VALUES('LM','1999-02-08');
INSERT INTO employees VALUES('ZY','1972-06-09');
INSERT INTO employees VALUES('WZH','1999-02-28');
SELECT name,birthday FROM employees
-- 普通的 SQL 实现
SELECT
name,
birthday,
GETDATE() getdate,
CONVERT(VARCHAR(10),GETDATE(),120) todayVarchar,
CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120)) todayDateTime,
DATEDIFF(YY,birthday,GETDATE()) DateBetween,
DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday) ThisBirthday,
DATEADD(YY,DATEDIFF(YY,birthday,GETDATE())+1,birthday) NextBirthday,
CASE WHEN CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120))>DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday)
THEN DATEADD(YY,DATEDIFF(YY,birthday,GETDATE())+1,birthday)
ELSE DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday)
END newBirthdayStandard,
CASE WHEN CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120))>DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday)
THEN DATEADD(YY,DATEDIFF(YY,birthday,GETDATE())+1,birthday)+
CASE WHEN DAY(birthday)=29 AND DAY(DATEADD(YY,DATEDIFF(YY,birthday,GETDATE())+1,birthday))=28 THEN 1 ELSE 0 END
ELSE DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday) +
CASE WHEN DAY(birthday)=29 AND DAY(DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday))=28 THEN 1 ELSE 0 END
END newBirthdayForeign
FROM employees
-- 使用函数来实现
CREATE FUNCTION GetBirthday(@birthday DATETIME,@flag INT)
RETURNS DATETIME
AS
BEGIN
DECLARE @BirthdayRet DATETIME,@BirthdayThis DATETIME,@BirthdayNext DATETIME,@today DATETIME,@dateBetween INT
SET @today=CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120))
SET @dateBetween=DATEDIFF(YY,@birthday,GETDATE())
SET @BirthdayThis=DATEADD(YY,@DateBetween,@birthday)
SET @BirthdayNext=DATEADD(YY,@DateBetween+1,@birthday)
IF @flag=1 --2 月 29 日的生日计算为 2 月 28 日
BEGIN
IF @today>@BirthdayThis
SET @BirthdayRet=@BirthdayNext
ELSE
SET @BirthdayRet=@BirthdayThis
END
ELSE --2 月 29 日的生日计算为 3 月 1 日
BEGIN
IF @today>@BirthdayThis
IF DAY(@birthday)=29 AND DAY(@BirthdayNext)=28
SET @BirthdayRet=@BirthdayNext+1
ELSE
SET @BirthdayRet=@BirthdayNext
ELSE
IF DAY(@birthday)=29 AND DAY(@BirthdayThis)=28
SET @BirthdayRet=@BirthdayThis+1
ELSE
SET @BirthdayRet=@BirthdayThis END
RETURN @BirthdayRet
END
SELECT name,birthday,dbo.GetBirthday(birthday,0),dbo.GetBirthday(birthday,1) FROM employees
-- 通过 CTE 来实现
WITH DateBetween AS
(
SELECT
name,
birthday,
GETDATE() getdate,
CONVERT(VARCHAR(10),GETDATE(),120) todayVarchar,
CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120)) todayDateTime,
DATEDIFF(YY,birthday,GETDATE()) DateBetween
FROM employees
),
DateBirthdayThisAndNext AS
(
SELECT
name,birthday,getdate,todaydatetime,datebetween,
DATEADD(YY,DateBetween,birthday) AS DateCur,
DATEADD(YY,DateBetween+1,birthday) AS DateNext
FROM DateBetween
),
DateBirthdayThisAndNextForeign AS
(
SELECT
name,birthday,todaydatetime,
DateCur,DateNext,
DateCur+CASE WHEN DAY(birthday)=29 AND DAY(DateCur)=28 THEN 1 ELSE 0 END AS DateCurForeign,
DateNext+CASE WHEN DAY(birthday)=29 AND DAY(DateNext)=28 THEN 1 ELSE 0 END AS DateNextForeign
FROM DateBirthdayThisAndNext
),
DateBirthday AS
(
SELECT
name,birthday,
CASE WHEN DateCurForeign>=todaydatetime THEN DateCurForeign ELSE DateNextForeign END AS birthDayForeign,
CASE WHEN DateCur>=todaydatetime THEN DateCur ELSE DateNext END AS birthDayStandard
FROM DateBirthdayThisAndNextForeign
)
SELECT name,birthday,birthDayForeign,birthDayStandard FROM DateBirthday
主要的逻辑难点第一个是关于闰月尾天的计算,第二个是判断本年度生日是否已过
本文给出了三种解决办法,
第一种是最常用的解决办法,即常用的 SQL 语法,不过看起来比较复杂,适合环境为 SQLServer2000 以上
第二种是采用函数的方法,把对日期的逻辑处理放到函数中,调用起来会简约一下,适合环境为 SQLServer2000 以上
第三种是采用 CTE 的方法,用 CTE 来封装判断逻辑,适合环境为 SQLServer2005 以上
-- 创建表和数据
CREATE TABLE employees
(
name VARCHAR(50),
birthday DATETIME
)
INSERT INTO employees VALUES('WBQ','1948-12-08');
INSERT INTO employees VALUES('CZH','1952-02-19');
INSERT INTO employees VALUES('LB','1963-08-30');
INSERT INTO employees VALUES('YLL','1937-09-19');
INSERT INTO employees VALUES('YGQ','1955-03-04');
INSERT INTO employees VALUES('CHH','1963-07-02');
INSERT INTO employees VALUES('SWG','1960-05-29');
INSERT INTO employees VALUES('HW','1958-01-01');
INSERT INTO employees VALUES('YY','1972-02-29');
INSERT INTO employees VALUES('LM','1999-02-08');
INSERT INTO employees VALUES('ZY','1972-06-09');
INSERT INTO employees VALUES('WZH','1999-02-28');
SELECT name,birthday FROM employees
-- 普通的 SQL 实现
SELECT
name,
birthday,
GETDATE() getdate,
CONVERT(VARCHAR(10),GETDATE(),120) todayVarchar,
CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120)) todayDateTime,
DATEDIFF(YY,birthday,GETDATE()) DateBetween,
DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday) ThisBirthday,
DATEADD(YY,DATEDIFF(YY,birthday,GETDATE())+1,birthday) NextBirthday,
CASE WHEN CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120))>DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday)
THEN DATEADD(YY,DATEDIFF(YY,birthday,GETDATE())+1,birthday)
ELSE DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday)
END newBirthdayStandard,
CASE WHEN CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120))>DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday)
THEN DATEADD(YY,DATEDIFF(YY,birthday,GETDATE())+1,birthday)+
CASE WHEN DAY(birthday)=29 AND DAY(DATEADD(YY,DATEDIFF(YY,birthday,GETDATE())+1,birthday))=28 THEN 1 ELSE 0 END
ELSE DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday) +
CASE WHEN DAY(birthday)=29 AND DAY(DATEADD(YY,DATEDIFF(YY,birthday,GETDATE()),birthday))=28 THEN 1 ELSE 0 END
END newBirthdayForeign
FROM employees
-- 使用函数来实现
CREATE FUNCTION GetBirthday(@birthday DATETIME,@flag INT)
RETURNS DATETIME
AS
BEGIN
DECLARE @BirthdayRet DATETIME,@BirthdayThis DATETIME,@BirthdayNext DATETIME,@today DATETIME,@dateBetween INT
SET @today=CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120))
SET @dateBetween=DATEDIFF(YY,@birthday,GETDATE())
SET @BirthdayThis=DATEADD(YY,@DateBetween,@birthday)
SET @BirthdayNext=DATEADD(YY,@DateBetween+1,@birthday)
IF @flag=1 --2 月 29 日的生日计算为 2 月 28 日
BEGIN
IF @today>@BirthdayThis
SET @BirthdayRet=@BirthdayNext
ELSE
SET @BirthdayRet=@BirthdayThis
END
ELSE --2 月 29 日的生日计算为 3 月 1 日
BEGIN
IF @today>@BirthdayThis
IF DAY(@birthday)=29 AND DAY(@BirthdayNext)=28
SET @BirthdayRet=@BirthdayNext+1
ELSE
SET @BirthdayRet=@BirthdayNext
ELSE
IF DAY(@birthday)=29 AND DAY(@BirthdayThis)=28
SET @BirthdayRet=@BirthdayThis+1
ELSE
SET @BirthdayRet=@BirthdayThis END
RETURN @BirthdayRet
END
SELECT name,birthday,dbo.GetBirthday(birthday,0),dbo.GetBirthday(birthday,1) FROM employees
-- 通过 CTE 来实现
WITH DateBetween AS
(
SELECT
name,
birthday,
GETDATE() getdate,
CONVERT(VARCHAR(10),GETDATE(),120) todayVarchar,
CONVERT(DATETIME,CONVERT(VARCHAR(10),GETDATE(),120)) todayDateTime,
DATEDIFF(YY,birthday,GETDATE()) DateBetween
FROM employees
),
DateBirthdayThisAndNext AS
(
SELECT
name,birthday,getdate,todaydatetime,datebetween,
DATEADD(YY,DateBetween,birthday) AS DateCur,
DATEADD(YY,DateBetween+1,birthday) AS DateNext
FROM DateBetween
),
DateBirthdayThisAndNextForeign AS
(
SELECT
name,birthday,todaydatetime,
DateCur,DateNext,
DateCur+CASE WHEN DAY(birthday)=29 AND DAY(DateCur)=28 THEN 1 ELSE 0 END AS DateCurForeign,
DateNext+CASE WHEN DAY(birthday)=29 AND DAY(DateNext)=28 THEN 1 ELSE 0 END AS DateNextForeign
FROM DateBirthdayThisAndNext
),
DateBirthday AS
(
SELECT
name,birthday,
CASE WHEN DateCurForeign>=todaydatetime THEN DateCurForeign ELSE DateNextForeign END AS birthDayForeign,
CASE WHEN DateCur>=todaydatetime THEN DateCur ELSE DateNext END AS birthDayStandard
FROM DateBirthdayThisAndNextForeign
)
SELECT name,birthday,birthDayForeign,birthDayStandard FROM DateBirthday
相关文章推荐
- 关于SQLServer2005的学习笔记——生日问题
- 关于SQLServer2005的学习笔记——生日问题
- 关于SQLServer2005的学习笔记——多触发器执行问题
- 关于SQLServer2005的学习笔记——树形结构问题
- 关于SQLServer2005的学习笔记——多触发器执行问题
- 关于SQLServer2005的学习笔记——统计学自动分组问题
- 关于SQLServer2005的学习笔记——树形结构问题
- 关于SQLServer2005的学习笔记——统计学自动分组问题
- 关于SQLServer2005的学习笔记——统计学自动分组问题
- OSG学习笔记18 - 关于物体绕指定点旋转的问题(非坐标轴原点)
- 关于SQLServer2005的学习笔记——子查询
- 关于SQLServer2005的学习笔记——异常捕获及处理
- 关于SQLServer2005的学习笔记(一)——前言
- [Silverlight学习笔记]关于用户注册之后不能直接登录的问题
- 【个人学习笔记8之--关于OVER子句 多属性的比较 PIVOT 聚合问题】
- [openCV学习笔记]——关于waitKey(0)不起作用的问题
- 关于aircrack-ng的一些学习笔记及问题
- 工作学习笔记——一些关于链接的有趣小问题
- 关于SQLServer2005的学习笔记——自定义分组的实现