SQL 计算日期范围内的连续天数
SQL Counting Consecutive Days in Date Ranges
我正在尝试计算一个人可能拥有的连续天数,唯一的问题是我有日期范围而不是直接的日期列表。这是我所说的范围的示例:
Name Start_Date End_Date
Johnny 2020-01-02 2020-01-04
Johnny 2020-01-05 2020-01-05
Johnny 2020-01-06 2020-01-10
Jenny 2020-02-07 2020-02-07
Jenny 2020-02-10 2020-02-11
Jenny 2020-02-12 2020-02-12
开始日期和结束日期是 2 列中的一个范围。
我想要达到的结果是这样的:
Johnny has 9 consecutive days
Jenny has 3 consecutive days
我遇到过一些解决方案示例,但找不到适合我的日期范围问题的解决方案。
到目前为止使用的代码示例:
WITH
dates(date, employee_number) AS (
SELECT DISTINCT CAST(start_date AS DATE), name
FROM myTABLE
WHERE name = "Jenny"
),
groups AS (
SELECT
ROW_NUMBER() OVER (ORDER BY date) AS rn, name,
dateadd(day, -ROW_NUMBER() OVER (ORDER BY date), date) AS grp,
date
FROM dates
)
SELECT
name,
COUNT(*) AS consecutiveDates,
MIN(date) AS minDate,
MAX(date) AS maxDate
FROM groups
GROUP BY grp, name
这是一个 gaps-and-islands 问题。一种选择是使用 lag()
和 window sum()
来构建相邻记录组。然后,您可以按组汇总并计算连续天数,最后按名称过滤最大的连胜:
select name, max(consecutive_days) consecutive_days
from (
select name, datediff(day, min(start_date), max(end_date)) + 1 consecutive_days
from (
select t.*,
sum(case when start_date = dateadd(day, 1, lag_end_date) then 0 else 1 end) over(partition by name order by start_date) grp
from (
select t.*,
lag(end_date) over(partition by name order by start_date) lag_end_date
from mytable t
) t
) t
group by name, grp
) t
group by name
name | consecutive_days
:----- | ---------------:
Jenny | 3
Johnny | 9
像这样的东西应该有用。将 sub-selects 替换为您的 table.
select name, DATEDIFF(dd, MIN(Start_date),MAX(end_date)) +1 from
(
select a.name,a.start_date,b.end_date from
(SELECT 'Johnny' name , '2020-01-02' start_date, '2020-01-04' end_date
UNION SELECT 'Johnny' , '2020-01-05', '2020-01-05'
UNION SELECT 'Johnny' , '2020-01-06', '2020-01-10'
UNION SELECT 'Jenny' , '2020-02-07', '2020-02-07'
UNION SELECT 'Jenny' , '2020-02-10', '2020-02-11'
UNION SELECT 'Jenny' , '2020-02-12', '2020-02-12') a
LEFT join (SELECT 'Johnny' name , '2020-01-02' start_date, '2020-01-04' end_date
UNION SELECT 'Johnny' , '2020-01-05', '2020-01-05'
UNION SELECT 'Johnny' , '2020-01-06', '2020-01-10'
UNION SELECT 'Jenny' , '2020-02-07', '2020-02-07'
UNION SELECT 'Jenny' , '2020-02-10', '2020-02-11'
UNION SELECT 'Jenny' , '2020-02-12', '2020-02-12') b on DATEADD(dd,1,a.end_date ) = b.start_date and a.name = b.name
)q
group by name
我正在尝试计算一个人可能拥有的连续天数,唯一的问题是我有日期范围而不是直接的日期列表。这是我所说的范围的示例:
Name Start_Date End_Date
Johnny 2020-01-02 2020-01-04
Johnny 2020-01-05 2020-01-05
Johnny 2020-01-06 2020-01-10
Jenny 2020-02-07 2020-02-07
Jenny 2020-02-10 2020-02-11
Jenny 2020-02-12 2020-02-12
开始日期和结束日期是 2 列中的一个范围。
我想要达到的结果是这样的:
Johnny has 9 consecutive days
Jenny has 3 consecutive days
我遇到过一些解决方案示例,但找不到适合我的日期范围问题的解决方案。
到目前为止使用的代码示例:
WITH
dates(date, employee_number) AS (
SELECT DISTINCT CAST(start_date AS DATE), name
FROM myTABLE
WHERE name = "Jenny"
),
groups AS (
SELECT
ROW_NUMBER() OVER (ORDER BY date) AS rn, name,
dateadd(day, -ROW_NUMBER() OVER (ORDER BY date), date) AS grp,
date
FROM dates
)
SELECT
name,
COUNT(*) AS consecutiveDates,
MIN(date) AS minDate,
MAX(date) AS maxDate
FROM groups
GROUP BY grp, name
这是一个 gaps-and-islands 问题。一种选择是使用 lag()
和 window sum()
来构建相邻记录组。然后,您可以按组汇总并计算连续天数,最后按名称过滤最大的连胜:
select name, max(consecutive_days) consecutive_days
from (
select name, datediff(day, min(start_date), max(end_date)) + 1 consecutive_days
from (
select t.*,
sum(case when start_date = dateadd(day, 1, lag_end_date) then 0 else 1 end) over(partition by name order by start_date) grp
from (
select t.*,
lag(end_date) over(partition by name order by start_date) lag_end_date
from mytable t
) t
) t
group by name, grp
) t
group by name
name | consecutive_days :----- | ---------------: Jenny | 3 Johnny | 9
像这样的东西应该有用。将 sub-selects 替换为您的 table.
select name, DATEDIFF(dd, MIN(Start_date),MAX(end_date)) +1 from
(
select a.name,a.start_date,b.end_date from
(SELECT 'Johnny' name , '2020-01-02' start_date, '2020-01-04' end_date
UNION SELECT 'Johnny' , '2020-01-05', '2020-01-05'
UNION SELECT 'Johnny' , '2020-01-06', '2020-01-10'
UNION SELECT 'Jenny' , '2020-02-07', '2020-02-07'
UNION SELECT 'Jenny' , '2020-02-10', '2020-02-11'
UNION SELECT 'Jenny' , '2020-02-12', '2020-02-12') a
LEFT join (SELECT 'Johnny' name , '2020-01-02' start_date, '2020-01-04' end_date
UNION SELECT 'Johnny' , '2020-01-05', '2020-01-05'
UNION SELECT 'Johnny' , '2020-01-06', '2020-01-10'
UNION SELECT 'Jenny' , '2020-02-07', '2020-02-07'
UNION SELECT 'Jenny' , '2020-02-10', '2020-02-11'
UNION SELECT 'Jenny' , '2020-02-12', '2020-02-12') b on DATEADD(dd,1,a.end_date ) = b.start_date and a.name = b.name
)q
group by name