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');
使用join
和union
和format
如下
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。
我有两个参数:
@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');
使用join
和union
和format
如下
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。