首页 > 解决方案 > 在 SQL 中为迭代创建行

问题描述

我必须创建一个报告,说明每个月的第一天一张票打开多长时间,另一个显示关闭一张票需要多长时间。在不为每个月创建间隔的情况下,使用 SQL 执行此操作的最佳方法是什么?我正在使用 SQL Server 2008 R2

我目前的数据:

| Ticket | Start Date | End Date   |
|--------|------------|------------|
| ABC    | 5/8/2018   | 9/28/2018  |
| XYZ    | 6/22/2018  | 10/15/2018 |

预期结果:

| Ticket | Start Date | End Date   | Report Date | Ticket Age | Ticket Interval |
|--------|------------|------------|-------------|------------|-----------------|
| ABC    | 5/8/2018   | 9/28/2018  | 6/1/2018    | 24         |                 |
| ABC    | 5/8/2018   | 9/28/2018  | 7/1/2018    | 54         |                 |
| ABC    | 5/8/2018   | 9/28/2018  | 8/1/2018    | 85         |                 |
| ABC    | 5/8/2018   | 9/28/2018  | 9/1/2018    | 116        |                 |
| ABC    | 5/8/2018   | 9/28/2018  | 10/1/2018   |            | 143             |
| XYZ    | 6/22/2018  | 10/15/2018 | 7/1/2018    | 9          |                 |
| XYZ    | 6/22/2018  | 10/15/2018 | 8/1/2018    | 40         |                 |
| XYZ    | 6/22/2018  | 10/15/2018 | 9/1/2018    | 71         |                 |
| XYZ    | 6/22/2018  | 10/15/2018 | 10/1/2018   | 101        |                 |
| XYZ    | 6/22/2018  | 10/15/2018 | 11/1/2018   |            | 115             |

标签: sqlsql-serversql-server-2008sql-server-2008-r2

解决方案


您可以使用递归 CTE:

with cte as (
      select ticket, sdate, edate, dateadd(month, 1, dateadd(day, 1 - day(sdate), sdate)) as reportdate
      from t
      union all
      select ticket, sdate, edate, dateadd(month, 1, reportdate)
      from cte
      where reportdate <= edate
     )
select cte.*, datediff(day, sdate, reportdate) as ticketage,
       (case when datediff(month, edate, reportdate) = 1 then datediff(day, sdate, edate) end) as interval
from cte
order by ticket, reportdate;

我在票的最后一个月包括了票龄。case如果您真的不想要它,您可以使用类似的表达方式。

是一个 db<>fiddle。


推荐阅读