【问题标题】:Find nearest day of week for a given date and day of week查找给定日期和星期几的最近星期几
【发布时间】:2021-06-29 10:16:33
【问题描述】:

对于一对日期(date1, date2) = (Fri 2021-01-01, Wed 2020-01-01),我需要从 date1(本例中为星期五)中提取星期几,然后为 date2 找到最近的星期五(或其他日期)。

上述对的结果将是 Fri 2020-01-03(该星期三后 2 天)而不是 Fri 2019-12-27(该星期三前 5 天)。

有些示例可以查找上一个/下一个星期,使用硬编码的星期几或使用SET DATEFIRST 语句;所有这些我都必须避免。这是一些测试数据——日期和预期结果:

CREATE TABLE #tests (
    date1 DATE,
    date2 DATE,
    result DATE
);

INSERT INTO #tests(date1, date2, result) VALUES
(/*Fri*/ '2021-01-01', /*Wed*/ '2020-01-01', /*Fri*/ '2020-01-03'),
(/*Sat*/ '2021-01-02', /*Thu*/ '2020-01-02', /*Sat*/ '2020-01-04'),
(/*Sun*/ '2021-01-03', /*Fri*/ '2020-01-03', /*Sun*/ '2020-01-05'),
(/*Mon*/ '2021-01-04', /*Sat*/ '2020-01-04', /*Mon*/ '2020-01-06'),
(/*Tue*/ '2021-01-05', /*Sun*/ '2020-01-05', /*Tue*/ '2020-01-07'),
(/*Wed*/ '2021-01-06', /*Mon*/ '2020-01-06', /*Wed*/ '2020-01-08'),
(/*Thu*/ '2021-01-07', /*Tue*/ '2020-01-07', /*Thu*/ '2020-01-09');

INSERT INTO #tests(date1, date2, result) VALUES
(/*Fri*/ '2021-01-01', /*Sun*/ '2017-01-01', /*Fri*/ '2016-12-30'),
(/*Sat*/ '2021-01-02', /*Mon*/ '2017-01-02', /*Sat*/ '2016-12-31'),
(/*Sun*/ '2021-01-03', /*Tue*/ '2017-01-03', /*Sun*/ '2017-01-01'),
(/*Mon*/ '2021-01-04', /*Wed*/ '2017-01-04', /*Mon*/ '2017-01-02'),
(/*Tue*/ '2021-01-05', /*Thu*/ '2017-01-05', /*Tue*/ '2017-01-03'),
(/*Wed*/ '2021-01-06', /*Fri*/ '2017-01-06', /*Wed*/ '2017-01-04'),
(/*Thu*/ '2021-01-07', /*Sat*/ '2017-01-07', /*Thu*/ '2017-01-05');

【问题讨论】:

  • 您是否有权/自行决定创建日历维度表,其中包含从 1900 到 2100 的星期几数据?这将大大简化问题。
  • @Error_2646 我有一个和/或我可以修改它。
  • 两个日期输入是否会是一周中的同一天 - 就像星期三一样?如果是这样,它应该返回下一个星期三还是只返回相同的第二个输入日期?
  • @error 同一日期。预计输入中的任何日期

标签: sql date tsql


【解决方案1】:

假设您可以创建/修改日历维度,这就是您所追求的吗?

WITH
DAY_OF_WEEK_CALENDAR AS
  ( SELECT CAST('2021-04-01' AS DATE) AS date_id, 'Thursday' AS day_of_week UNION
    SELECT CAST('2021-04-02' AS DATE), 'Friday' UNION
    SELECT CAST('2021-04-03' AS DATE), 'Saturday' UNION
    SELECT CAST('2021-04-04' AS DATE), 'Sunday' UNION
    SELECT CAST('2021-04-05' AS DATE), 'Monday' UNION
    SELECT CAST('2021-04-06' AS DATE), 'Tuesday' UNION
    SELECT CAST('2021-04-07' AS DATE), 'Wednesday' UNION
    SELECT CAST('2021-04-08' AS DATE), 'Thursday' UNION
    SELECT CAST('2021-04-09' AS DATE), 'Friday' UNION
    SELECT CAST('2021-04-10' AS DATE), 'Saturday' UNION
    SELECT CAST('2021-04-11' AS DATE), 'Sunday' UNION
    SELECT CAST('2021-04-12' AS DATE), 'Monday' UNION
    SELECT CAST('2021-04-13' AS DATE), 'Tuesday' UNION
    SELECT CAST('2021-04-14' AS DATE), 'Wednesday'
  ),
  TEST AS 
  ( SELECT CAST('2021-04-02' AS DATE) AS date_1,
           CAST('2021-04-10' AS DATE) AS date_2
      UNION
    SELECT CAST('2021-04-04' AS DATE) AS date_1,
           CAST('2021-04-10' AS DATE) AS date_2
  )
SELECT TEST.*,
       ( SELECT TOP 1 date_id
           FROM DAY_OF_WEEK_CALENDAR DOW_2
          WHERE DOW_2.date_id BETWEEN DATEADD(day,-7,TEST.date_2)
                   AND DATEADD(day,7,TEST.date_2)
            AND DOW_1.day_of_week = DOW_2.day_of_week
          ORDER
             BY DATEDIFF(day,DOW_2.date_id,TEST.date_2) ASC
       ) AS nearest_date_match
  FROM TEST
 INNER
  JOIN DAY_OF_WEEK_CALENDAR DOW_1
    ON TEST.date_1 = DOW_1.date_id

【讨论】:

  • 稍微调整一下 between 子句就不需要 Top 1 和 order by!
  • @SalmanA 有趣的是,您是如何通过调整 between 子句来使其工作的?我想不出该怎么做。
【解决方案2】:

原来很简单:

对于Wed 2020-01-01,计算-3 天和+3 天,这样您就有一个由7 天组成的日期范围,中间是星期三:

[Sun 2019-12-29 ... Wed 2020-01-01 ... Sat 2020-01-04]

这个范围包含一周中最接近星期三的所有日子;您只需要过滤所需的星期几。这可以通过蛮力(子查询)来完成,或者通过使用公式进一步加/减一些天数。要根据另一个日期查找星期几,公式为:

addto_date2_minus3days = (DATEPART(WEEKDAY, date1) - DATEPART(WEEKDAY, date2_minus3days) + 7) % 7

查询OP中的样本数据:

SELECT
    FORMAT(date1, 'ddd yyyy-MM-dd') AS date1,
    FORMAT(date2, 'ddd yyyy-MM-dd') AS date2,
    FORMAT(nearest_date, 'ddd yyyy-MM-dd') AS [nearest_dow(date1, date2)]
FROM #tests
CROSS APPLY (
    SELECT DATEADD(DAY, -3, date2) AS date2_minus3days
) AS ca1
CROSS APPLY (
    SELECT DATEADD(DAY, (DATEPART(WEEKDAY, date1) - DATEPART(WEEKDAY, date2_minus3days) + 7) % 7, date2_minus3days) AS nearest_date
) AS ca2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-23
    • 1970-01-01
    • 2015-10-10
    • 2011-03-02
    相关资源
    最近更新 更多