最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

sql server - Burndown chart using rows between current row and unbounded following - Stack Overflow

programmeradmin3浏览0评论

I have a SQL Server table that looks like this:

Fix Date    Risk Level  Issue Count
------------------------------------
2/28/25        High        4
3/31/25      Critical      1
3/31/25        High        4
4/30/25        High        2
5/31/25        High        3
6/30/25      Critical      1
6/30/25        High        4
7/31/25        High        2
8/31/25        High        1
9/30/25        High        2
10/31/25     Critical      1
10/31/25       High        1
11/30/25       High        1
12/31/25       High        1
3/31/26        High        1

I am creating a burndown chart that shows the active issue counts by Fix date and risk level. Using the table above, this means on 2/28/25 the projected count is the total-i.e, 26 High and 3 Critical; on 3/31 the projected count remaining would be 22 High and 3 Critical; on 4/30/25 the projected count remaining would be 18 High and 2 Critical, etc.
This is the SQL query

Select fix_date, risk_level, sum(issue_count) over (partition by risk_level 
order by fix_date rows between current row and unbounded following)

The result of the SQL query should look like this, so I could then plot it.:

Fix Date    Risk Level  Issue Count
-----------------------------------
2/28/25       High         26
2/28/25     Critical        3
3/31/25       High         22
3/31/25     Critical        3
4/30/25       High         18
4/30/25     Critical        2
5/31/25       High         16
5/31/25     Critical        2
6/30/25       High         13
6/30/25     Critical        2
7/31/25       High          9
7/31/25     Critical        1
8/30/25       High          7
8/30/25     Critical        1
9/30/25       High          6
9/30/25     Critical        1
10/31/25      High          4
10/31/25    Critical        1
11/30/25      High          3
12/31/25      High          2
1/31/26       High          1
2/28/26       High          1
3/31/26       High          1

I am using the rows between current row and unbounded following clause, but the results are only showing a value of Critical for a month if there is one in the table for it for that month. I need two records for each month, one for High and one for Critical, and if there isn't a value for Critical in a month there still should be a record for it for that month and the value should be what it was in the prior month there was a value.

Do I need to create some kind of date table and join to this table?

I have a SQL Server table that looks like this:

Fix Date    Risk Level  Issue Count
------------------------------------
2/28/25        High        4
3/31/25      Critical      1
3/31/25        High        4
4/30/25        High        2
5/31/25        High        3
6/30/25      Critical      1
6/30/25        High        4
7/31/25        High        2
8/31/25        High        1
9/30/25        High        2
10/31/25     Critical      1
10/31/25       High        1
11/30/25       High        1
12/31/25       High        1
3/31/26        High        1

I am creating a burndown chart that shows the active issue counts by Fix date and risk level. Using the table above, this means on 2/28/25 the projected count is the total-i.e, 26 High and 3 Critical; on 3/31 the projected count remaining would be 22 High and 3 Critical; on 4/30/25 the projected count remaining would be 18 High and 2 Critical, etc.
This is the SQL query

Select fix_date, risk_level, sum(issue_count) over (partition by risk_level 
order by fix_date rows between current row and unbounded following)

The result of the SQL query should look like this, so I could then plot it.:

Fix Date    Risk Level  Issue Count
-----------------------------------
2/28/25       High         26
2/28/25     Critical        3
3/31/25       High         22
3/31/25     Critical        3
4/30/25       High         18
4/30/25     Critical        2
5/31/25       High         16
5/31/25     Critical        2
6/30/25       High         13
6/30/25     Critical        2
7/31/25       High          9
7/31/25     Critical        1
8/30/25       High          7
8/30/25     Critical        1
9/30/25       High          6
9/30/25     Critical        1
10/31/25      High          4
10/31/25    Critical        1
11/30/25      High          3
12/31/25      High          2
1/31/26       High          1
2/28/26       High          1
3/31/26       High          1

I am using the rows between current row and unbounded following clause, but the results are only showing a value of Critical for a month if there is one in the table for it for that month. I need two records for each month, one for High and one for Critical, and if there isn't a value for Critical in a month there still should be a record for it for that month and the value should be what it was in the prior month there was a value.

Do I need to create some kind of date table and join to this table?

Share Improve this question edited Mar 15 at 14:15 52414246 asked Mar 15 at 0:43 5241424652414246 112 bronze badges 3
  • Show us your full attempt not just part of it. The snippet of SQL you showed us is part of a windowed function, however, without the rest of it we don't why it's not doing what you expect. – Thom A Commented Mar 15 at 10:09
  • A reasonable chart should be able to handle missing points, but yeah, a calendar table join and some lag/leads should probably solve your issue – siggemannen Commented Mar 15 at 11:03
  • SQL statement added. I believe I may need to write new SQL that uses a calendar table and join it to this table to get this to work – 52414246 Commented Mar 15 at 14:16
Add a comment  | 

1 Answer 1

Reset to default 0

Yes, you will need either a calendar table or a date range generator to fill in the missing rows. For SQL Server 2022 and later, the GENERATE_SERIES(), DATE_ADD(), and EOMONTH() functions can be used to generate a range of EOM dates, after the start, end, and difference are identified in a subquery using MIN() and MAX().

If you cross join the dates with DISTINCT risk_level values, you can then use the CROSS APPLY (SELECT TOP 1 ...) pattern to look up the appropriate value from your intermediate results.

With Dates As (
    Select eomonth(dateadd(month, S.value, MM.fix_date_min)) As fix_date
    From (
        Select
            min(R.fix_date) As fix_date_min,
            datediff(month, min(R.fix_date), max(R.fix_date)) As fix_date_diff
        From ResolvedIssues R
    ) MM
    Cross Apply generate_series(0, MM.fix_date_diff) S
),
RiskLevels As (
    Select Distinct R.risk_level
    From ResolvedIssues R
),
CummulativeResolvedIssues As (
    Select
        fix_date,
        risk_level,
        sum(issue_count)
            over (partition by risk_level 
                  order by fix_date
                  rows between current row and unbounded following)
            As issue_count
    From ResolvedIssues
)
Select
    D.fix_Date,
    R.risk_level,
    C1.issue_count
From Dates D
Cross Join RiskLevels R
Cross Apply (
    Select Top 1 C.*
    From CummulativeResolvedIssues C
    Where C.risk_level = R.risk_level
    And C.fix_Date >= D.fix_Date
    Order By C.fix_Date
) C1
Order By D.fix_date, R.risk_level

If using a SQL Server version prior to 2022, a recursive CTE can instead be be used to generate the date series.

With Dates As (
    Select
        eomonth(min(R.fix_date)) As fix_date,
        eomonth(max(R.fix_date)) As last_fix_date
    From ResolvedIssues R
    Union All
    Select
        eomonth(dateadd(day, 1, D.fix_date)) As fix_date,
        last_fix_date
    From Dates D
    Where D.fix_date < D.last_fix_date
),
...

Results (same for both versions):

fix_Date risk_level issue_count
2025-02-28 Critical 3
2025-02-28 High 26
2025-03-31 Critical 3
2025-03-31 High 22
2025-04-30 Critical 2
2025-04-30 High 18
2025-05-31 Critical 2
2025-05-31 High 16
2025-06-30 Critical 2
2025-06-30 High 13
2025-07-31 Critical 1
2025-07-31 High 9
2025-08-31 Critical 1
2025-08-31 High 7
2025-09-30 Critical 1
2025-09-30 High 6
2025-10-31 Critical 1
2025-10-31 High 4
2025-11-30 High 3
2025-12-31 High 2
2026-01-31 High 1
2026-02-28 High 1
2026-03-31 High 1

If you wish to also generate 0 rows for the "Critical" cases at the end of the date sequence, you can change the Cross Apply or Outer Apply and change the C1.issue_count select item to ISNULL(C1.issue_count, 0) As issue_count.

This will add the following rows to the results.

fix_Date risk_level issue_count
... ... ...
2025-11-30 Critical 0
2025-12-31 Critical 0
2026-01-31 Critical 0
2026-02-28 Critical 0
2026-03-31 Critical 0

See this db<>fiddle for a demo.

发布评论

评论列表(0)

  1. 暂无评论