【问题标题】:SQL Server: calculating date rangesSQL Server:计算日期范围
【发布时间】:2011-04-04 13:55:26
【问题描述】:

我正在尝试获取从本月初(上一年)到当天(上一年)的日期范围。有没有办法简化这段代码?

SELECT 'From the beginning of month to this day, previous year' AS Label,
       CONVERT (DATETIME, CAST (DATEPART(YY, GETDATE()) - 1 AS CHAR (4)) + CASE 
                                                                           WHEN DATEPART(MM, GETDATE()) < 10 THEN '-0' + CAST (DATEPART(MM, GETDATE()) AS CHAR (1)) ELSE '-' + CAST (DATEPART(MM, GETDATE()) AS CHAR (2)) 
                                                                           END + '-01') AS Begin_date,
       CONVERT (DATETIME, CAST (DATEPART(YY, GETDATE()) - 1 AS CHAR (4)) + CASE 
                                                                           WHEN DATEPART(MM, GETDATE()) < 10 THEN '-0' + CAST (DATEPART(MM, GETDATE()) AS CHAR (1)) ELSE '-' + CAST (DATEPART(MM, GETDATE()) AS CHAR (2)) 
                                                                           END + CASE 
                                                                                 WHEN DATEPART(DD, GETDATE()) < 10 THEN '-0' + CAST (DATEPART(DD, GETDATE()) AS CHAR (1)) ELSE '-' + CAST (DATEPART(DD, GETDATE()) AS CHAR (2)) 
                                                                                 END) AS End_date

【问题讨论】:

  • begin_date 应该是 '20100401'?

标签: sql sql-server tsql sql-server-2008


【解决方案1】:
SELECT  'Anything' as Label
        ,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0) as firstdaythismonth
        ,DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) as today
        ,DATEADD(year, -1, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)) as firstdaythismonth_lastyear
        ,DATEADD(year, -1, DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)) as today_lastyear

【讨论】:

  • +1 :在我看来,使用 DateAdd 和 DateDiff 优于 Convert。它产生了一种一致且灵活的方法。
  • @Dems:谢谢,这也是我的意见。
【解决方案2】:
SELECT 
     DATEADD(yy, -1, CONVERT(VARCHAR(25),
     DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()),101)) AS Date_Value,
     'First Day of Current Month Of Last Year' AS Date_Type
UNION
SELECT 
     DATEADD(yy, -1, GETDATE()) AS TodayLastYear, 'Today Last Year'

或者如果你只想要值而不需要描述

SELECT 
     DATEADD(yy, -1, CONVERT(VARCHAR(25),
     DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()),101))
UNION
SELECT 
     DATEADD(yy, -1, GETDATE()) AS TodayLastYear

您使用 DATEADD 并指定 yy 来减去年份。只需使用负值即可。

我还将分享一组我使用的常用日期函数。只需将其创建为表值函数即可:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go

CREATE FUNCTION [dbo].[udfCommonDates] (@date datetime)
RETURNS @t table (week_start datetime,
                  week_end datetime,
                  lastweek_start datetime,
                  lastweek_end datetime,
                  month_start datetime,
                  month_end datetime,
                  lastmonth_start datetime,
                  lastmonth_end datetime,
                  yesterday_start datetime,
                  yesterday_end datetime,
                  today_start datetime,
                  today_end datetime,
                  thisweek_monday_start datetime,
                  thisweek_monday_end datetime,
                  year_start datetime,
                  year_end datetime,
                  tomorrow_noon datetime,
                  today_noon datetime,
                  date_only datetime)
BEGIN
   INSERT @t
   SELECT
   dbo.get_week_start ( @date ) AS week_start,
   dbo.get_week_end   ( @date ) AS week_end,
   dbo.get_week_start ( DATEADD(d, -7, @date ) ) AS lastweek_start,
   dbo.get_week_end   ( DATEADD(d, -7, @date ) ) AS lastweek_end,
   dbo.get_month_start( @date ) AS month_start,
   dbo.get_month_end  ( @date ) AS month_end,
   dbo.get_month_start ( DATEADD(m,-1, @date) ) AS lastmonth_start,
   dbo.get_month_end  ( DATEADD(m,-1,@date) ) AS lastmonth_end,
   dbo.get_yesterday_start ( @date ) AS yesterday_start,
   dbo.get_yesterday_end ( @date ) AS yesterday_end,
   dbo.get_today_start (@date) AS today_start,
   dbo.get_today_end ( @date ) AS today_end,
   dbo.get_weekday_start(1,@date) AS thisweek_monday_start,
   dbo.get_weekday_end(1,@date) AS thisweek_monday_end,
   dbo.get_year_start(@date) AS year_start,
   dbo.get_year_end(@date) AS year_end,  
   dbo.get_tomorrow_noon(@date) AS TomorrowNoon,
   dbo.get_today_noon(@date) AS TodayNoon,
   dbo.get_date_only(@date) AS DateOnly
RETURN
END

以下是这些的标量值函数:

    CREATE FUNCTION [dbo].[get_date_only] (@date datetime)
    RETURNS datetime
    WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
    AS    
    BEGIN
        RETURN dateadd(day, DateDiff(day, 0, GetDate()), 0)
    END
    GO

CREATE FUNCTION [dbo].[get_month_end] (@date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    
BEGIN
   RETURN dateadd(ms, -3, dateadd (m,datediff(m,0,
          dateadd(m,1,@date)),0))
END
GO

CREATE FUNCTION [dbo].[get_month_start] (@date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    
BEGIN
   RETURN dateadd(m,datediff(m,0, @date),0)
   END
GO

CREATE FUNCTION [dbo].[get_today_end] (@today datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    
BEGIN
   return dateadd(ms, -3, datediff(d,0,dateadd(d,1,@today)))
END
GO

CREATE FUNCTION [dbo].[get_today_noon](@date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   RETURN DATEADD(hh, 12, DATEADD(d,DATEDIFF(d,0, @date),0))
END
GO

CREATE FUNCTION [dbo].[get_today_start] (@today datetime)
RETURNS datetime 
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   return dateadd(day, 0, datediff(d,0,@today))
END
GO

CREATE FUNCTION [dbo].[get_tomorrow_noon](@date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   RETURN DATEADD(hh, 12, DATEADD(d,DATEDIFF(d,-1, @date),0))
END
GO

CREATE FUNCTION [dbo].[get_week_end] (@date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   return dateadd(yyyy, datepart(yyyy,
      dateadd(weekday,7-datepart(weekday, @date),@date))-1900, 0)
    + dateadd(ms, -3,
      dateadd(dy, datepart(dy,
     dateadd(weekday,7-datepart(weekday, @date),@date)),0) )
END
GO

CREATE FUNCTION [dbo].[get_week_start] (@date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   return dateadd(yyyy, datepart(yyyy,
      dateadd(weekday,1-datepart(weekday, @date),@date))-1900, 0)
    + dateadd(dy, datepart(dy,
      dateadd(weekday,1-datepart(weekday, @date),@date))-1,0)
END
GO

CREATE FUNCTION [dbo].[get_weekday_end] (@weekday tinyint,
                                 @date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   return dateadd(yyyy, datepart(yyyy,
      dateadd(weekday,@weekday-
      datepart(weekday, @date),@date))-1900, 0)
    + dateadd(ms, -3,
      dateadd(dy, datepart(dy,
      dateadd(weekday,@weekday-datepart(weekday, @date),
                                        @date)),0) )
END
GO

CREATE FUNCTION [dbo].[get_weekday_start] (@weekday tinyint,
                                   @date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   return dateadd(yyyy, datepart(yyyy,
      dateadd(weekday,@weekday-
      datepart(weekday, @date),@date))-1900, 0)
    + dateadd(dy, datepart(dy,
      dateadd(weekday,@weekday-datepart(weekday, @date),
                                        @date))-1,0)
END
GO

CREATE FUNCTION [dbo].[get_year_end] (@date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
RETURN DATEADD(year, DATEDIFF(year, 0, GetDate())+1, 0)-1
END
GO

CREATE FUNCTION [dbo].[get_year_start] (@date datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   RETURN DATEADD(year,DATEDIFF(year,0, @date),0)
END
GO

CREATE FUNCTION [dbo].[get_yesterday_end] (@today datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   return dateadd(ms, -3, datediff(d,0,@today))
END
GO

CREATE FUNCTION [dbo].[get_yesterday_start] (@today datetime)
RETURNS datetime
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS    BEGIN
   RETURN dateadd(day, -1, datediff(d,0,@today))
END
GO

这些对我真的很有帮助,因为我在报告服务中使用了它来获取日期参数。您可以简单地创建一个引用此表函数的数据集,然后在 RS 中的任何日期时间的参数中使用它们。

您可以像这样执行整个表值函数:

SELECT * FROM [MyDB].[dbo].[udfCommonDates] (GetDate())

结果是这样的

报告服务人员

现在我之前提到我将这些用于报告服务。 现在 RS 人员可能在想,但这对我有什么帮助,因为我需要一个数据集,而数据集只能基于存储过程或直接表。创建以下存储过程没问题:

CREATE PROCEDURE [dbo].[uspCommonDates] AS
begin
   set datefirst 1
   declare @date datetime
   set @date = getdate()
   select * from dbo.udfCommonDates(@date)
end

现在您已经有了一个可用作数据集的存储过程...现在在报告服务中添加一个新数据集:

现在转到报告的报告参数部分:

现在选择该数据集 dsFunctions(或您所称的任何名称),然后从标量函数中选择任何值字段,例如:

现在,当您运行报告时,它使用标量:

【讨论】:

  • @JonH - 你的一些函数不使用输入日期,但是getdate()
  • @Johan - 这很正常,例如,当您在寻找年终时,您在日历年中使用哪个日期并不重要。您也可以将@date 用于该特定日期。
  • 仅供参考,他们可能都应该有WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
  • @Martin - 修改以满足您的需求。
【解决方案3】:

您可以使用 DATEADD 函数来提供帮助:

 SELECT 'From the beginning of month to this day, previous year' AS Label,
DATEADD(YY,-1,DATEADD(DD,-(day(getdate())-1),DATEDIFF(dd, 0, GETDATE()))) AS Begin_date,
DATEADD(YY,-1,DATEDIFF(dd, 0, GETDATE()))  AS End_date

【讨论】:

  • 这给出了 begin_date 的 '20110401'
【解决方案4】:

对于 2010-04-01 , 2010-04-04 怎么样;

SELECT 
CAST(DATEADD(DAY, -365 + -(DAY(GETDATE())-1), GETDATE()) AS DATE), 
CAST(DATEADD(YEAR, -1, GETDATE()) AS DATE)  

【讨论】:

  • 29-feb 将返回 28-feb for lys,据我所知
  • 您的解决方案在 2012 年 3 月至 2013 年 2 月期间不起作用。试试吧。它会说一个月的第一天是第二天。
  • 对不起,我不是故意挑剔的,但在某些应用程序中,仅仅休息一天就会导致一切变得混乱。在大多数情况下,您的解决方案已经足够好,具体取决于应用程序的状态。我提出这个问题的唯一原因是我见过使用常数的代码,例如 365(一年中的天数),但问题是我们并不生活在如此完美的世界中:)。
  • 不,你完全正确,我只是写了 -day 偏移量,并认为在不考虑闰年的情况下再取消 365 会更简单!
【解决方案5】:
SELECT  'From the beginning of month to this day, previous year' AS Label,
        CONVERT(DATETIME,LEFT(CONVERT(VARCHAR(6),DATEADD(YEAR,-1,GETDATE()),112),6)+'01') Begin_date,
        DATEADD(YEAR,-1,GETDATE()) End_date

【讨论】:

  • 我不喜欢您必须在解决方案中使用的字符串转换/连接/子字符串和特定日期格式。
猜你喜欢
  • 1970-01-01
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多