目录
介绍
背景
日期
日期范围
用范围填充日期
周
周范围
用范围填充周数
更改周开始日
月
月份范围
使用范围填充月份
年
年份范围
用范围填充年份
日期时间函数
创建函数
使用函数
其他
DateTime Now
DateTime To Date
日,月,年详细信息
名称
数值
添加日期
加一天
推迟一秒
扣除毫秒
按日期分组
在报告列表/返回基于日期时间属性标记的数据时,通常需要。这些可能包括创建各种报告,如每日,每周,每月,每年等。本文将特别帮助那些需要生成各种日期范围的人。文章和示例侧重于DATETIME 数据类型。
我们会做什么?
查找日期的开始和结束日期时间。
DECLARE @dateTimeNow DATETIME ='2019-07-01 17:20:00' /*yyyy-MM-dd HH:mm:ss*/
--DECLARE @dateTimeNow DATETIME = GETDATE(); /*now*/
SELECT
[StartDateTime] = DATEADD(DAY, DATEDIFF(DAY, 0, @dateTimeNow), 0),
[EndDateTime] = DATEADD(SECOND, -1, DATEADD(DAY, DATEDIFF(DAY, 0, @dateTimeNow) + 1, 0));
生成具有每日范围的日期列表:
DECLARE @startDateTime DATETIME ='2019-09-21', _
@endDateTime DATETIME ='2019-09-30'; /*yyyy-MM-dd*/
--SET @startDateTime = GETDATE(); _
SET @endDateTime = @startDateTime + 10; /*now*/
WITH Dates([Date])
AS
(
SELECT [Date]= @startDateTime
UNION ALL
SELECT [Date] + 1
FROM Dates
WHERE [Date] + 1 <= @endDateTime
),
DateRange([Date], [StartDateTime], [EndDateTime])
AS
(
SELECT
[Date],
DATEADD(DAY, DATEDIFF(DAY, 0, [Date]), 0),
DATEADD(SECOND, -1, DATEADD(DAY, DATEDIFF(DAY, 0, [Date]) + 1, 0))
FROM Dates
)
SELECT *
FROM DateRange
OPTION (MAXRECURSION 0)
查找一周的开始和结束日期时间。
DECLARE @dateTimeNow DATETIME ='2019-07-01' /*yyyy-MM-dd*/
--DECLARE @dateTimeNow DATETIME = GETDATE(); /*now*/
SELECT
[StartDate] = DATEADD(dd, -(DATEPART(WEEKDAY, @dateTimeNow)-1), _
DATEADD(dd, DATEDIFF(dd, 0, @dateTimeNow), 0)),
[EndDate] = DATEADD(dd, 7-(DATEPART(WEEKDAY, @dateTimeNow)), _
DATEADD(dd, DATEDIFF(dd, 0, @dateTimeNow), 0));
SELECT
[StartDateTime] = DATEADD(DAY, -(DATEPART(WEEKDAY, @dateTimeNow)-1), _
DATEADD(DAY, DATEDIFF(DAY, 0, @dateTimeNow), 0)),
[EndDateTime] = DATEADD(DAY, 7-(DATEPART(WEEKDAY, @dateTimeNow)), _
DATEADD(SECOND, -1, DATEADD(DAY, DATEDIFF(DAY, 0, @dateTimeNow) + 1, 0)))
生成具有每周范围的周列表:
DECLARE @startDateTime DATETIME = '2019-04-01 03:20:00', _
@endDateTime DATETIME = '2019-04-30 03:20:00';
WITH Weeks([Date])
AS
(
SELECT [Date] = @startDateTime
UNION ALL
SELECT DATEADD(DAY, 7, [Date])
FROM Weeks
WHERE DATEADD(DAY, 7, [Date]) <= @endDateTime
),
WeekRange([Date], [StartDateTime], [EndDateTime])
AS
(
SELECT
[Date],
DATEADD(DAY, -(DATEPART(WEEKDAY, [Date])-1), _
DATEADD(DAY, DATEDIFF(DAY, 0, [Date]), 0)),
DATEADD(DAY, 7-(DATEPART(WEEKDAY, [Date])), _
DATEADD(SECOND, -1, DATEADD(DAY, DATEDIFF(DAY, 0, [Date]) + 1, 0)))
FROM Weeks
)
SELECT *
FROM WeekRange
OPTION (MAXRECURSION 0)
在SQL Server中,星期日是默认的星期开始日。有一个@@DATEFIRST函数,它返回当前的周开始日期(SET DATEFIRST的值)。要更改默认的周开始日,我们可以将任何周开始日期设置为1-7 到DATEFIRST之间的值。在设定了预期的周开始日之后,我们所有人都在查询上运行。
SELECT @@DATEFIRST;
SET DATEFIRST 7; /*setting week start to 'Sunday'*/
@@DATEFIRST是会话的本地。我们可以通过在SQL Server Management Studio中打开不同的选项卡并在不同的选项卡中执行set / select代码来验证它。对于选项,请检查SQL Server:查找周开始和结束日期时间。
查找一个月的开始和结束日期时间。
DECLARE @dateTimeNow DATETIME ='2019-07-01'; /*yyyy-MM-dd*/
--DECLARE @dateTimeNow DATETIME = GETDATE(); /*now*/
SELECT
[StartDate] = DATEADD(mm, DATEDIFF(m, 0, @dateTimeNow), 0),
[EndDate] = DATEADD(mm, DATEDIFF(m, 0, @dateTimeNow) + 1, -1);
SELECT
[StartDateTime] = DATEADD(mm, DATEDIFF(m, 0, @dateTimeNow), 0),
[EndDateTime] = DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, @dateTimeNow) + 1, 0));
生成月度范围的月份列表:
DECLARE @startDateTime DATETIME ='2019-01-18 03:20:00', _
@endDateTime DATETIME ='2019-12-18 04:20:00';
WITH Months([Date])
AS
(
SELECT [Date] = @startDateTime
UNION ALL
SELECT DATEADD(MONTH, 1, [Date])
FROM Months
WHERE DATEADD(MONTH, 1, [Date]) <= @endDateTime
),
MontRange([Date], [StartDateTime], [EndDateTime])
AS
(
SELECT
[Date],
DATEADD(mm, DATEDIFF(m, 0, [Date]), 0),
DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, [Date]) + 1, 0))
FROM Months
)
SELECT *
FROM MontRange
OPTION (MAXRECURSION 0)
查找一年的开始和结束日期时间。
DECLARE @dateTimeNow DATETIME ='2019-07-01' /*yyyy-MM-dd*/
--DECLARE @dateTimeNow DATETIME = GETDATE(); /*now*/
SELECT
[StartDate] = DATEADD(yy, DATEDIFF(yy, 0, @dateTimeNow), 0),
[EndDate] = DATEADD(yy, DATEDIFF(yy, 0, @dateTimeNow) + 1, -1)
SELECT
[StartDateTime] = DATEADD(yy, DATEDIFF(yy, 0, @dateTimeNow), 0),
[EndDateTime] = DATEADD(s, -1, DATEADD(yy, DATEDIFF(yy, 0, @dateTimeNow) + 1, 0))
生成具有年度范围的年份列表:
DECLARE @startDateTime DATETIME ='2017-12-17 03:20:00', _
@endDateTime DATETIME ='2019-12-19 04:20:00';
WITH Years([Date])
AS
(
SELECT [Date] = @startDateTime
UNION ALL
SELECT DATEADD(YEAR, 1, [Date])
FROM Years
WHERE DATEADD(YEAR, 1, [Date]) <= @endDateTime
),
YearRange([Date], [StartDateTime], [EndDateTime])
AS
(
SELECT
[Date],
DATEADD(yy, DATEDIFF(yy, 0, [Date]), 0),
DATEADD(s, -1, DATEADD(yy, DATEDIFF(yy, 0, [Date]) + 1, 0))
FROM Years
)
SELECT *
FROM YearRange
OPTION (MAXRECURSION 0)
多次重复相同的代码后,我想知道为什么不创建一个日期时间辅助函数来查找开始/结束日期时间。所以我们来创建它。
IF OBJECT_ID(N'DateTimePart', N'FN') IS NOT NULL
DROP FUNCTION DateTimePart;
GO
CREATE FUNCTION DateTimePart(@dateTime DATETIME, @startOrEnd VARCHAR(10))
RETURNS DATETIME
AS
BEGIN
/*validations*/
IF @dateTime IS NULL
BEGIN
RETURN @dateTime;
END
IF @startOrEnd NOT IN('Start', 'End')
BEGIN
RETURN CAST('@startOrEnd should be IN(Start, End)' AS INT);
END
/*result*/
DECLARE @result DATETIME;
SELECT @result =
CASE @startOrEnd
WHEN 'Start' THEN DATEADD(DAY, DATEDIFF(DAY, 0, @dateTime), 0)
WHEN 'End' THEN DATEADD(SECOND, -1, _
DATEADD(DAY, DATEDIFF(DAY, 0, @dateTime) + 1, 0))
END;
RETURN @result;
END
DECLARE @dateTime DATETIME ='2019-12-01 17:20:00' /*yyyy-MM-dd HH:mm:ss*/
SELECT
[DateTime] = @dateTime,
[StartDateTime] = dbo.DateTimePart(@dateTime, 'start'),
[EndDateTime] = dbo.DateTimePart(@dateTime, 'end');
SELECT
[Local] = GETDATE(),
[Utc] = GETUTCDATE();
SELECT
[Date] = CONVERT(DATE, GETDATE()), --CONVERT(DATE, GETDATE(), 101)
[Date] = CAST(GETDATE() AS DATE),
[DateTime] = DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0); --DAY
SELECT
[Day] = DATENAME(WEEKDAY, GETDATE()),
[Month] = DATENAME(MONTH, GETDATE()),
[Year] = DATENAME(YEAR, GETDATE());
SELECT
[Day] = DATEPART(WEEKDAY, GETDATE()),
[Month] = DATEPART(MONTH, GETDATE()),
[Year] = DATEPART(YEAR, GETDATE());
SELECT
[Today] = GETDATE(),
[TodayPlusOneDayUsingFunction] = DATEADD(dd, 1, GETDATE()), /*addsing one day*/
[TodayPlusOneDayUsingOperator] = GETDATE() + 1; /*addsing one day*/
SELECT
[NowDateTime] = GETDATE(),
[StatDateTime] = DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0), /*removing time details*/
[EndDateTime] = DATEADD(SECOND, -1, DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) + 1, 0)); /*removing time details, adding one date(+1), deducting one second(-1)*/
要添加/减去MILLISECOND/MICROSECOND/NANOSECOND,最好将源/结果转换为DATETIME2对象而不是DATETIME。
SELECT
[NowDateTime] = GETDATE(),
DATEADD(MILLISECOND, -1, DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) + 1, 0)), /*not as expected, went to next date*/
/*
MICROSECOND, MICROSECOND, NANOSECOND need DATETIME2, better to use DATETIME2 data type
Datetime2 Vs Datetime: https://stackoverflow.com/questions/1334143/datetime2-vs-datetime-in-sql-server
*/
DATEADD(MILLISECOND, -1, CAST(DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) + 1, 0) AS DATETIME2)),
DATEADD(MICROSECOND, -1, CAST(DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) + 1, 0) AS DATETIME2)),
DATEADD(NANOSECOND, -1, CAST(DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) + 1, 0) AS DATETIME2));
DECLARE @tblTest TABLE(AddDateTime DATETIME NOT NULL);
INSERT
INTO @tblTest
VALUES
/*yyyy-MM-dd hh:mm:ss*/
('2019-04-17 03:20:00'),
('2019-04-17 04:20:00'),
('2019-04-16 03:20:00'),
('2019-04-16 04:20:00')
SELECT
[Date] = DATEADD(dd, DATEDIFF(dd, 0, AddDateTime), 0),
[Total] = COUNT(AddDateTime)
FROM @tblTest
GROUP BY DATEADD(dd, DATEDIFF(dd, 0, AddDateTime), 0);
原文地址:https://www.codeproject.com/Articles/5161688/SQL-Server-DateTime-Range-Pro