加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

SQLserver2005 中日期类型的使用全功略

发布时间:2020-12-12 15:49:54 所属栏目:MsSql教程 来源:网络整理
导读:日期类型有两种 datetime 和 smalldatetime. datetime的存储方式:共用8个字节来存放,前四个字节用于存放 距1900-1-1相隔的天数。 ????? 后四个字节存入午夜到现在经过的时间,精确到 3又三分之一毫秒。 ????? 时间跨度:从1753-01-01~9999-12-31号 ? smalld

日期类型有两种 datetime 和 smalldatetime.

datetime的存储方式:共用8个字节来存放,前四个字节用于存放 距1900-1-1相隔的天数。
????? 后四个字节存入午夜到现在经过的时间,精确到 3又三分之一毫秒。

????? 时间跨度:从1753-01-01~9999-12-31号
?
smalldatetime:共用4个字节来存放,前2个字节用于存放 距1900-1-1相隔的天数。
??????? 后2个字节存入午夜到现在经过的时间,精确到分钟.
??????? 时间跨度:从1900-01-01~2079-6-6号?

日期格式可以由以下几个方面来影响:
?SET LANGUAGE,SET DATEFORMAT

下面两种表示方法不受set 选项的影响:
?1.[yy]yymmdd[ hh:mi[:ss][.mmm]]
?2.'yyyy-mm-ddThh:mi:ss[.mmm]' 如:'2006-02-12T14:23:05'

也有这种形式,{d '2006-02-12'}. ,与set选项无关,仅供API使用.

日期类型的精度演示如下:
?比如将'20060923 03:23:47.001' 转化为datetime类型
?select select cast('20060923 03:23:47.001' as datetime)
?得到的结果为2006-09-23 03:23:47.000,丢失了0.001的精度。
?如果转化为smalldatetime,则精度丢失的更多:
?select select cast('20060923 03:23:47.001' as smalldatetime)
?结果为2006-09-23 03:24:00,秒精度全部丢失。

要特别注意,因为datetime的精度问题,所以datetime的毫秒部分的格式应如下:
? [0-9][0-9][037] ,smalldatetime则只能到分钟.
所以要取出一整天的时间,只能这样写,
?WHERE dt BETWEEN '20060211 00:00:00.000' AND '20060211 23:59:59.997'
而不应该写成
?WHERE dt BETWEEN '20060211 00:00:00.000' AND '20060211 23:59:59.999'
? 等同于WHERE dt BETWEEN '20060211 00:00:00.000' AND '20060212 00:00:00.000'
或直接写成这样,
??WHERE dt >= '20060211 00:00:00.000' AND dt < '20060212 00:00:00.000'

下面列举几个方面的应用示例:
?1。生日问题,可以用如下的解决方案:检查今年员工是否已经过完了生日,过完后取下一年的生日,
没过完则取今年的生日.(引用northwind数据库)

with arg1
as
(
select lastname,firstname,birthdate,Diff=datediff(year,getdate()),
CAST(CONVERT(CHAR(8),GETDATE(),112) AS DATETIME) AS Today from dbo.Employees
),
?arg2
as
(
?select lastname,Today,BCur=dateadd(year,diff,birthdate),
??? bNext=dateadd(year,diff+1,birthdate) from arg1
),
arg3
as
(
?select? lastname,??---处理二月份的月底
?BCur= BCur+case when day(birthdate)=29 and day(BCur)=28 then 1 else 0 end,
?bNext= bNext+case when day(birthdate)=29 and day(bNext)=28 then 1 else 0 end
?from arg2
)
select lastname,
BirthDay=(case when BCur>=Today then BCur else BNext end) from arg3

2.时间交迭问题,表结构及测试数据如下:
?USE tempdb;
GO
IF OBJECT_ID('dbo.Sessions') IS NOT NULL
? DROP TABLE dbo.Sessions;
GO

CREATE TABLE dbo.Sessions
(
? keycol??? INT???????? NOT NULL IDENTITY PRIMARY KEY,
? app?????? VARCHAR(10) NOT NULL,
? usr?????? VARCHAR(10) NOT NULL,
? starttime DATETIME??? NOT NULL,
? endtime?? DATETIME??? NOT NULL,
? CHECK(endtime > starttime)
);

INSERT INTO dbo.Sessions(app,usr,starttime,endtime)
? VALUES('app1','user1','20060212 08:30','20060212 10:30');
INSERT INTO dbo.Sessions(app,'user2','20060212 08:45');
INSERT INTO dbo.Sessions(app,'20060212 09:00','20060212 09:30');
INSERT INTO dbo.Sessions(app,'20060212 09:15','20060212 10:30','20060212 14:30');
INSERT INTO dbo.Sessions(app,'20060212 10:45','20060212 11:30');
INSERT INTO dbo.Sessions(app,'20060212 11:00','20060212 12:30');
INSERT INTO dbo.Sessions(app,endtime)
? VALUES('app2','20060212 11:45','20060212 12:00');
INSERT INTO dbo.Sessions(app,'20060212 12:30','20060212 14:00');
INSERT INTO dbo.Sessions(app,'20060212 12:45','20060212 13:30');
INSERT INTO dbo.Sessions(app,'20060212 13:00','20060212 14:00','20060212 16:30');
INSERT INTO dbo.Sessions(app,'20060212 15:30','20060212 17:00');

CREATE UNIQUE INDEX idx_app_usr_s_e_key
? ON dbo.Sessions(app,endtime,keycol);
CREATE INDEX idx_app_s_e ON dbo.Sessions(app,endtime);
GO
??
?? 1)求出有重叠的两个时间段的组合,有交迭则表示一段的开始一定在另一段的开始时间与结束时间之间
??? 可以用如下语句来实现。
?? select app1=s1.app,usr1=s1.usr,key1=s1.keycol,start1=s1.starttime,end1=s1.endtime
,key2=s2.keycol,start2=s2.starttime,end2=s2.endtime
from Sessions s1
inner join Sessions s2
?on s1.app=s2.app and s1.usr=s2.usr
and s1.keycol<>s2.keycol
and (s1.starttime between s2.starttime and s2.endtime
or s2.starttime between s1.starttime and s1.endtime)

?? 2)如果要合并重迭项为一项,则首先要分别得到不在重迭区域的开始时间及结束时间.再分别组合,得到一个无重复的
????? 系列.
??? ?with starttime
as
(
?select distinct app,starttime from dbo.Sessions s
?where not exists
?(
??select 1 from dbo.Sessions a
??where s.app=a.app and s.usr=a.usr
??and s.starttime>a.starttime
??and s.starttime<=a.endtime
?)
),
endtime
as
(
?select distinct app,endtime from dbo.Sessions s
?where not exists
?(
??select 1 from dbo.Sessions a
??where s.app=a.app and s.usr=a.usr
??and s.endtime>=a.starttime
??and s.endtime<a.endtime
?)
)
select app,
endtime=(select min(endtime) from endtime
where starttime.app=endtime.app and starttime.usr=endtime.usr
and starttime.starttime<=endtime.endtime
)
?from starttime

?? 3)求出同时在线的人数最大值(相当于是找出每个开始时间在其他时段之间的最大个数)

with arg
as(
select app,
?num=(select count(1) from dbo.Sessions b
?where a.app=b.app and a.starttime>=b.starttime
?and a.starttime<b.endtime
?)
from (SELECT DISTINCT app,starttime
???? FROM dbo.Sessions) as a
)

select? app,最多在线人数=max(num) from arg
group by app;

也可以用子表来表示如下所示:

select? app,最多在线人数=max(num) from
(
select app,starttime
???? FROM dbo.Sessions) as a
)a
group by a.app

3.求指定日期是本星期的第几天,一般我们使用
DATEPART 来进行处理,但datepart返回的结果会受set datefirst的影响,设置不同返回值也不同,
所以可以用这种方式来避免设置值的不确定性.
DATEPART(weekday,dt + @@DATEFIRST - n)
其中n:表示你想要让@@datefirst设置的值

也可以用与指定日期的间隔天数来求得
SELECT OrderID,OrderDate
FROM dbo.Orders
WHERE DATEDIFF(day,'19000102',OrderDate) % 7 = 0;

比如说要一个指定日期的星期开始时间与星期结束时间可以这样:

declare @testdate datetime
set @testdate='2008-08-10';

select 星期开始=@testdate-datepart(dw,@testdate+@@datefirst-1)+1,
今天=convert(char(10),@testdate,120),
星期结束=@testdate-datepart(dw,@testdate+@@datefirst-1)+7


4.工作日与非工作日问题。
? 如果除了休息日外,还有其他节日,自定的休假日期的话,一般来说是添加一个存放休息日的辅助表来实现,
如果只有星期六或星期日为休息日的话,求工作日可以这样:

DECLARE @s AS DATETIME,@e AS DATETIME;
SET @s = '20080811';
SET @e = '20080823';

select days/7*5+days%7?-case when 6 between wd and wd+days%7-1 then 1 else 0 end?-case when 7 between wd and wd+days%7-1 then 1 else 0 endfrom(select days=datediff(day,@s,@e)+1,?wd=datepart(dw,@s+@@datefirst-1))a

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读