【问题标题】:T-SQL date pickupT-SQL 日期取件
【发布时间】:2017-07-12 07:04:51
【问题描述】:

我正在寻找一些 T-SQL 代码,它应该选择“从当前日期回溯一年(1 月的最后一个星期日)”的日期。

我有一些 T-SQL 代码正在 SQL Server 2014 中使用:

select 
    convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(GetDate()) = 1 THEN CONVERT(VARCHAR(4), GetDate(), 112) - 1 ELSE CONVERT(VARCHAR(4), GetDate(), 112) END), 112) + '0101')), 30)) / 7  * 7, '19000107'), 120)

上面的代码选择了当年的日期(一月的最后一个星期日)。但我希望 T-SQL 代码选择去年(1 月的最后一个星期日的日期)的日期。

详细说明 - 我希望 T-SQL 代码从下表中生成 预期结果

Current day             Expected result
---------------------------------------
2017-02-05              2016-01-31
2017-01-05              2015-01-25
2018-02-19              2017-01-29
2018-01-19              2016-01-31
2019-02-28              2018-01-28

请注意,年份总是从“一月的最后一个星期日”开始。

【问题讨论】:

    标签: sql sql-server sql-server-2008 date sql-server-2012


    【解决方案1】:

    会有更简洁的解决方案,但是当我们假设您的代码经过时间考验且稳健时,我会简单地将 GETDATE() 替换为现在减去一年的表达式:

    DATEADD(year, -1, GETDATE())
    

    因此:

    SELECT
      convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(DATEADD(year,-1,GetDate())) = 1 THEN CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) - 1 ELSE CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) END), 112) + '0101')), 30)) / 7  * 7, '19000107'), 120)
    

    【讨论】:

      【解决方案2】:

      这将使用数据隔离列。

      请试一试告诉我。谢谢。

          select 
          convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(GetDate()) = 1 THEN CONVERT(VARCHAR(4), GetDate(), 112) - 1 ELSE CONVERT(VARCHAR(4), 
      GetDate(), 112) END), 112) + '0101')), 30)) / 7  * 7, '19000107'), 120) AS CurrentDay , convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(DATEADD(year,-1,GetDate())) = 1 THEN CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) - 1 ELSE CONVERT(VARCHAR(4), 
      DATEADD(year,-1,GetDate()), 112) END), 112) + '0101')), 30)) / 7  * 7, '19000107'), 120) as ExpectedResult
      

      【讨论】:

        【解决方案3】:

        如果您有日历表,则可以跳过第一个 CTE(可能还有 MAXRECURSION 选项),直接使用日历表。希望这是完全正确

        declare @today date
        set @today = CURRENT_TIMESTAMP
        
        ;With Dates as (
            select CONVERT(date,'19000101') as d
            union all
            select DATEADD(day,1,d) from Dates where d < '21000101'
        ), ApplicableSundays as (
            select d,ROW_NUMBER() OVER (ORDER BY d desc) as rn
            from Dates
            where d < @today and
            DATEPART(month,d) = 1 and
            DATEPART(weekday,d) = DATEPART(weekday,'20150913') and --Any known Sunday
            DATEPART(day,d) between 25 and 31
        )
        select d
        from ApplicableSundays where rn = 2
        option (maxrecursion 0)
        

        Dates 生成 20 世纪和 21 世纪的所有日期,希望对您的目的足够灵活。

        ApplicableSundays 将这些行过滤到出现在@today 之前的日期,在一月份,是星期天(使用已知的好日期,而不是依赖任何特定的 DATEFIRST 设置)并且介于 25 日和当月 31 日。

        然后我们选择第二个最近的日期,如果我们的年份从每年一月的最后一个星期日开始,则它必须是去年的开始。


        如果您正在处理一个充满日期的表,您希望找到这个“去年年初”值,您可以在ApplicableDates CTE 中将其作为join 引入,并对ROW_NUMBER() 进行分区使用这些值进行聚合,以便您可以并行查找所有星期日。

        【讨论】:

        • 伟大、正确和多才多艺。但是:我的答案的执行计划=一个节点,“选择不查询”。 this 的执行计划 = 一棵深度为 13 的树 :)
        • @dlatikay - 是的。我看过你的,但我仍然不确定实际的逻辑是什么。我的一些复杂性来自于想使用日历表,但另一方面又想提供一个独立的脚本。
        猜你喜欢
        • 2017-07-11
        • 2015-05-19
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-11
        • 2011-01-20
        • 1970-01-01
        相关资源
        最近更新 更多