SQL Server:专业的DateTime范围

目录

介绍

背景

日期

日期范围

用范围填充日期

周范围

用范围填充周数

更改周开始日

月份范围

使用范围填充月份

年份范围

用范围填充年份

日期时间函数

创建函数

使用函数

其他

DateTime Now

DateTime To Date

日,月,年详细信息

名称

数值

添加日期

加一天

推迟一秒

扣除毫秒

按日期分组


介绍

在报告列表/返回基于日期时间属性标记的数据时,通常需要。这些可能包括创建各种报告,如每日,每周,每月,每年等。本文将特别帮助那些需要生成各种日期范围的人。文章和示例侧重于DATETIME 数据类型。

背景

我们会做什么?

  • 查找一天的开始和结束日期时间
  • 用范围填充日期
  • 查找一周的开始和结束日期时间
  • 用范围填充周数
  • 查找一个月的开始和结束日期时间
  • 用范围填充月份
  • 查找一年的开始和结束日期时间
  • 用范围填充年份
  • 很少有其他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)

SQL Server:专业的DateTime范围_第1张图片

周范围

查找一周的开始和结束日期时间。

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)))

SQL Server:专业的DateTime范围_第2张图片

用范围填充周数

生成具有每周范围的周列表:

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:专业的DateTime范围_第3张图片

更改周开始日

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:查找周开始和结束日期时间

SQL Server:专业的DateTime范围_第4张图片

月份范围

查找一个月的开始和结束日期时间。

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));

SQL Server:专业的DateTime范围_第5张图片

使用范围填充月份

生成月度范围的月份列表:

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)

SQL Server:专业的DateTime范围_第6张图片

年份范围

查找一年的开始和结束日期时间。

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))

SQL Server:专业的DateTime范围_第7张图片

用范围填充年份

生成具有年度范围的年份列表:

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)

SQL Server:专业的DateTime范围_第8张图片

日期时间函数

多次重复相同的代码后,我想知道为什么不创建一个日期时间辅助函数来查找开始/结束日期时间。所以我们来创建它。

创建函数

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');

其他

DateTime Now

SELECT
    [Local] = GETDATE(),
    [Utc] = GETUTCDATE();

DateTime To Date

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

你可能感兴趣的:(数据库,SQL,Server,DateTime范围)