sql一个时间段在另一个时间段有多少天

sql how many days one period of time has in another period of time

我有两个参数:

@startDate date = N'2022-01-17'
@endDate date = N'2022-02-28'

还有一个带数据的table(与参数无关)

jobnr startdate duedate
nr324 2022-01-09 2022-01-19
nr326 2022-04-09 2022-05-13

任务是计算我的参数在 table 日期之间每个月发生的天数,并按参数月份 ((jan,february))

对它们进行分组

输出应该是这样的:

| JobNr  | Month      | How many days  |
|:-------|:----------:| --------------:|
| nr324  | January    |3               |              
| nr324  | February   |0               |
| nr326  | January    |0               |             
| nr326  | February   |0               |

** 3 是因为 17.01、18.01、19.01 处于 nr324 作业的选定时间段 其他为零,因为在@startDate date = N'2022-01-17' @endDate date = N'2022-02-28' 的选定时间段内没有发生任何事情。**

我不太明白。我知道在某个地方应该有我认为的时间差异,也许 window 函数。

declare @a table (
   jobnr     VARCHAR(6) NOT NULL 
  ,startdate DATE  NOT NULL
  ,duedate   DATE  NOT NULL
);
INSERT INTO @a(jobnr,startdate,duedate) VALUES 
('nr324','2022-01-09','2022-01-19'),
('nr326','2022-04-09','2022-05-13');

使用joinunionformat如下

DECLARE @startDate DATE = N'2022-01-17' --yourvariable
DECLARE @endDate DATE = N'2022-02-28' -- yourvariable

SELECT a.month1,
       Count(b.month1) AS 'How many days'
FROM   (SELECT Format(@startDate, 'MMMM') month1---month as name
        UNION
        SELECT Format(@endDate, 'MMMM') month1) a
       LEFT JOIN (SELECT jobnr,
                         startdate,
                         Format(startdate, 'MMMM') month1
                  FROM   @a --your table
                  UNION
                  SELECT jobnr,
                         duedate,
                         Format(duedate, 'MMMM') month1
                  FROM   @a) b
              ON a.month1 = b.month1
GROUP  BY b.month1,
          a.month1  

您在几个月的 CTE 方面走在正确的轨道上,但您需要注意结束条件,例如 2022-01-31 到 2022-02-01 的范围。从那里,您可以 CROSS JOIN 包含工作数据的日历,以计算工作、月份和总体范围之间的重叠日期数。

SQL 服务器没有 LEAST() 或 GREATEST() 函数来对离散值进行操作,因此需要另一种方法,对于两个值,可以使用简单的 CASE 语句,但是对于比较 3 个或更多值,该逻辑变得越来越复杂。使事情相对简单的一个技巧是使用 MIN() 和 MAX() 聚合函数对一组使用 VALUES 语法定义的数据进行操作。

从那里,您可以计算天数,注意避免出现负范围。

最终结果是这样的:

;WITH Months (Date) AS (
    SELECT DATEADD(DAY, 1 - DAY(@startdate), @startdate) -- First-of-month
    UNION ALL
    SELECT DATEADD(month, 1, Date)
    from months
    where DATEADD(month, 1, Date) <= @enddate -- Inclusive
)
SELECT
    JobNr = D.jobnr,
    Month = DATENAME(month, M.Date),
    [How Many Days] = CASE
        WHEN R.RangeStart <= R.RangeEnd
        THEN 1 + DATEDIFF(DAY, R.RangeStart, R.RangeEnd)
        ELSE 0
        END
FROM Months M
CROSS JOIN @Data D
OUTER APPLY(
    SELECT RangeStart = MAX(StartDate), RangeEnd = MIN(EndDate)
    FROM (
        VALUES
            (@startDate, @endDate),
            (M.Date, EOMONTH(m.Date)),
            (D.startdate, D.duedate)
    ) A(StartDate, EndDate)
) R
ORDER BY D.jobnr, M.Date

假定结束日期(@endDate 和 duedate)均包含在内。上述逻辑也适用于跨越多年的范围,您可能希望将 YEAR(M.Date) 添加到结果中。

有关演示,请参阅 this db<>fiddle