关于SQLServer2005的学习笔记——生日问题

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介:
生日问题是个看似简单逻辑上却又比较复杂的小问题
 
主要的逻辑难点第一个是关于闰月尾天的计算,第二个是判断本年度生日是否已过
 
本文给出了三种解决办法,
第一种是最常用的解决办法,即常用的 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 
 
 



本文转自baoqiangwang51CTO博客,原文链接:http://blog.51cto.com/baoqiangwang/310453 ,如需转载请自行联系原作者
相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
2月前
|
SQL 关系型数据库 MySQL
MySQL根据身份证获取省份 年龄 性别
MySQL根据身份证获取省份 年龄 性别
37 0
|
3月前
|
SQL 数据挖掘 数据处理
「SQL面试题库」 No_91 不同性别每日分数总计
「SQL面试题库」 No_91 不同性别每日分数总计
|
10月前
|
Java
关于用出生日期查询生日还有多少天的问题
关于用出生日期查询生日还有多少天的问题
87 0
|
SQL 关系型数据库 MySQL
【黄啊码】MySQL入门—3、我用select *,老板直接赶我坐火车回家去,买的还是站票
大家好!我是黄啊码,学会了DDL语句了吗?那我们今天就来学习一下基本的查询语法,我见过很多外包机构的程序员都是万物皆可select *,然后项目跑了一段时间就基本跑不动了,问就回答:服务器配置不够,加钱!好家伙,居然可以这样,学习啦【狗头保护】如果你在维护自家公司的项目,老板稍微会点技术,你相信他会打你吗?
101 0
【黄啊码】MySQL入门—3、我用select *,老板直接赶我坐火车回家去,买的还是站票
女兒,今天是你的生日
女兒,今天是你的生日。20年前的今天,你來到這個世界。   那天,睡得正香的我突然被你媽媽的呻吟聲驚醒。我扶著你媽媽悄悄起床, 走幾步,你這個搗蛋的小生命就要折騰你媽媽一下,她疼得蹲在地上,然後再慢慢站起來,可剛走幾步,又痛苦地蹲下去。
1232 0
|
人工智能 BI
生日相同
题目链接:http://ica.openjudge.cn/struct/1/ 总时间限制: 1000ms 内存限制: 65536kB 描述 在一个有180人的大班级中,存在两个人生日相同的概率非常大,现给出每个学生的名字,出生月日。
1435 0
|
网络协议 Java 数据库连接