【问题标题】:How to get 1st and 3rd Saturday and all Sunday between 2 dates using sql如何使用 sql 获取两个日期之间的第一个和第三个星期六和所有星期日
【发布时间】:2021-11-09 22:08:24
【问题描述】:

给定一个日期范围,我想返回该范围内的所有周六和周日,条件如下:

  • 仅当其序数位置是其所在月份的第一个或第三个星期六(不在整个范围内)时才包括星期六。
  • 包括所有星期日,以及该星期日在其所在月份内的序号位置

例如,如果开始日期是 2021 年 8 月 15 日,结束日期是 2021 年 9 月 20 日,则输出将是:

Dates         Saturday Number (in its own month)
----------    ---------------
2021-08-21    3
2021-09-04    1
2021-09-18    3

Dates         Sunday Number (in its own month)
----------    ---------------
2021-08-15    3
2021-08-22    4
2021-08-29    5
2021-09-05    1
2021-09-12    2
2021-09-19    3

然后我可以取日期范围的总和(37 天),然后从每个月 (3) 中减去星期日 (6) 和第一个和第三个星期六,以 28 结束。

试过这个查询

DECLARE @sd DATETIME = '2021-08-15'   DECLARE @ed DATETIME =
'2021-09-20'

--find first saturday WHILE DATEPART(dw, @sd)<>7 BEGIN  SET @sd = DATEADD(dd,1,@sd) END

--get next saturdays ;WITH Saturdays AS (
        --initial value     SELECT @sd AS MyDate, 1 AS SatNo    UNION ALL
        --recursive part    SELECT DATEADD(dd,7,MyDate) AS MyDate, CASE WHEN SatNo + 1 =6 THEN 1 ELSE SatNo+1 END AS SatNo  FROM Saturdays 
    WHERE DATEADD(dd,7,MyDate)<=@ed

) SELECT * FROM Saturdays  WHERE SatNo IN (1,3) OPTION(MAXRECURSION 0)

它不能正常工作。

也试过这个解决方案 Get number of weekends between two dates in SQL 计算工作日,但我只想要第 1 个和第 3 个星期六和所有星期日

【问题讨论】:

  • 如果您必须找到这样的任意结果,calendar table 会更简单。
  • 如果您只对日期感兴趣,为什么要使用 datetime 数据类型?想想!
  • @allmhuran 好吧,我更新了措辞,希望对未来的读者更清楚。
  • @AaronBertrand 是的,这似乎是正确和明确的。好多了!
  • 根据问题指南,请不要发布代码、数据、错误消息等的图像 - 将文本复制或输入到问题中。请保留将图像用于图表或演示渲染错误,无法通过文本准确描述的事情。

标签: sql sql-server tsql


【解决方案1】:

获取calendar table;它使此类业务问题变得轻而易举。这是一个更简单的:

CREATE TABLE dbo.Calendar
(
  TheDate date PRIMARY KEY,
  WeekdayName AS (CONVERT(varchar(8), DATENAME(WEEKDAY, TheDate))),
  WeekdayInstanceInMonth tinyint
);

;WITH x(d) AS -- populate with 2020 -> 2029
(
  SELECT CONVERT(date, '20200101')
  UNION ALL
  SELECT DATEADD(DAY, 1, d)
    FROM x 
    WHERE d < '20291231'
)
INSERT dbo.Calendar(TheDate)
  SELECT d FROM x
  OPTION (MAXRECURSION 0);

;WITH c AS 
(
  SELECT *, rn = ROW_NUMBER() OVER 
      (PARTITION BY YEAR(TheDate), MONTH(TheDate), WeekdayName 
       ORDER BY TheDate)
  FROM dbo.Calendar
)
UPDATE c SET WeekdayInstanceInMonth = rn;

现在您的查询很简单:

DECLARE @start date = '20210815', @end date = '20210920';

SELECT Dates = TheDate, 
       [Saturday Number] = WeekdayInstanceInMonth
  FROM dbo.Calendar 
  WHERE TheDate >= @start
    AND TheDate <= @end
    AND WeekdayName = 'Saturday'
    AND WeekdayInstanceInMonth IN (1,3);
    
SELECT Dates = TheDate,
       [Sunday Number] = WeekdayInstanceInMonth
  FROM dbo.Calendar 
  WHERE TheDate >= @start
    AND TheDate <= @end
    AND WeekdayName = 'Sunday';

结果(db<>fiddle example here):

Dates         Saturday Number
----------    ---------------
2021-08-21    3
2021-09-04    1
2021-09-18    3

Dates         Sunday Number
----------    ---------------
2021-08-15    3
2021-08-22    4
2021-08-29    5
2021-09-05    1
2021-09-12    2
2021-09-19    3

只得到数字 28:

DECLARE @start date = '20210815', @end date = '20210920';

SELECT DATEDIFF(DAY, @start, @end) + 1
- 
(SELECT COUNT(*)
  FROM dbo.Calendar 
  WHERE TheDate >= @start
    AND TheDate <= @end
    AND WeekdayName = 'Saturday'
    AND WeekdayInstanceInMonth IN (1,3))
- 
(SELECT COUNT(*)
  FROM dbo.Calendar 
  WHERE TheDate >= @start
    AND TheDate <= @end
    AND WeekdayName = 'Sunday');

【讨论】:

    【解决方案2】:

    假设datefirst 设置为星期日:

    (
        day(dt) + 
          datepart(weekday, dateadd(dt, 1 - day(dt))) % 7
    ) / 7 as SaturdayNumber,
    
    (
        day(dt) - 1 +
          datepart(weekday, dateadd(dt, 1 - day(dt)))
    ) / 7 as SundayNumber
    

    对于所有日期,这基本上计算了一个月内相对于周六/周日的周数 (0-5)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-18
      • 2017-05-02
      • 1970-01-01
      • 1970-01-01
      • 2019-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多