python-3.x 将一个多年合同行拆分为多个行,涵盖从开始日期到结束日期的1年/365天

ohfgkhjo  于 2023-02-10  发布在  Python
关注(0)|答案(2)|浏览(129)

我的合同编号1涵盖2022年8月1日至2024年7月31日,我需要将所有有效合同拆分为多行,每行涵盖365天/年。现有表-EX-合同1涵盖2022年8月1日至2024年7月31日,我需要将合同1从8/1/2022拆分到7/31/2023(在第1行),将合同1从8/1/2023拆分到7/31/2024(在第2行)(合同第二年)与wise第三年(2024年8月1日至2025年7月31日)相同。
| 合同|开始日期|结束日期|
| - ------|- ------|- ------|
| 1个|2022年8月1日|二〇二四年七月三十一日|
| 二十三|2022年8月7日|2023年8月8日|
| 二十六|2022年6月8日|2025年6月9日|
我需要上面的table分开
| S.No|合同|开始日期|结束日期|
| - ------|- ------|- ------|- ------|
| 1个|1个|2022年8月1日|二零二三年七月三十一日|
| 第二章|1个|2023年8月1日|二〇二四年七月三十一日|
| 三个|二十三|2022年8月7日|2023年8月8日|
| 四个|二十六|2022年6月8日|二〇二三年六月七日|
| 五个|二十六|2023年6月8日|2024年6月7日|
| 六个|二十六|2024年6月8日|2025年6月7日|

n6lpvg4x

n6lpvg4x1#

以下内容将确定任何合同的最大可能年数,生成一个数字序列0..N,计算每个合同的每个潜在全年,然后调整结果以反映实际合同结束日期。

-- Upper bound on number of years
DECLARE @MaxYears INT = (
    SELECT 1 + MAX(DATEDIFF(year, Start_date, End_date))
    FROM COntracts
)

;WITH NumTable AS (
    SELECT 0 AS N
    UNION ALL
    SELECT N + 1
    FROM NumTable
    WHERE N < @Maxyears
)
SELECT
    C.Contract,
    D.Start_Date,
    CASE WHEN D.End_date < C.End_date THEN D.End_date ELSE C.End_date END AS End_date
FROM Contracts C
CROSS APPLY (
    SELECT
        DATEADD(year, N.N, C.Start_date) AS Start_date,
        DATEADD(day, -1, DATEADD(year, N.N + 1, C.Start_date)) AS End_date
    FROM NumTable N
) D
WHERE D.Start_date <= C.End_date
ORDER BY C.Contract, D.Start_Date

如果使用SQL Server 2022,则可以将NumTable CTE替换为GENERATE_SERIES()函数,并且可以将CASE表达式替换为LEAST()

SELECT C.Contract, D.Start_Date, LEAST(D.End_date, C.End_date) AS End_date
FROM Contracts C
CROSS APPLY (
    SELECT
        DATEADD(year, S.Value, C.Start_date) AS Start_date,
        DATEADD(day, -1, DATEADD(year, S.Value + 1, C.Start_date)) AS End_date
    FROM GENERATE_SERIES(0, DATEDIFF(year, C.Start_date, C.End_date)) S
) D
WHERE D.Start_date <= C.End_date
ORDER BY C.Contract, D.Start_Date

结果:
| 合同|开始日期|结束日期|
| - ------|- ------|- ------|
| 1个|2022年8月1日|二〇二三年七月三十一日|
| 1个|2023年8月1日|二○二四年七月三十一日|
| 二十三|2022年8月7日|二〇二三年八月六日|
| 二十三|2023年8月7日|2023年8月8日|
| 二十六|2022年6月8日|二〇二三年六月七日|
| 二十六|二〇二三年六月八日|二○二四年六月七日|
| 二十六|二○二四年六月八日|二〇二五年六月七日|
| 二十六|二○二五年六月八日|二○二五年六月九日|
上述结果与OP要求的结果略有不同,但我认为根据所述要求,这是正确的。
参见this db<>fiddle

    • 极端情况:**如果合同从闰年的2月29日开始,计算将把下一年的开始日期定义为28日或29日,并可能有一个从2月28日到下一个闰年的2月28日的366天的下一个合同年。
11dmarpk

11dmarpk2#

您可以尝试以下递归CTE:

with cte as
(
  select Contract, start_date sd, end_date ed, DATEADD(year, 1, start_date) new_ed
  from table_name
  where end_date >= GETDATE() -- get only active contracts
  union all
  select Contract, new_ed, ed, DATEADD(year, 1, new_ed)
  from cte
  where new_ed < DATEADD(day, -1, ed)
)
select ROW_NUMBER() over (order by Contract, sd) [S.No],
       Contract,
       sd start_date,
       iif(YEAR(ed) = YEAR(new_ed), ed, DATEADD(day, -1, new_ed)) end_date
from cte
order by Contract, sd

See demo

相关问题