显示考虑连续几周的数据

Show data that takes into consideration consecutive weeks

你好我有这样的情况我基本上需要写一个SQL这样的语句的代码

select *,
    case when 'Issue' IN ('Overforecasted', 'Underforecasted') AND 'Start Date' DISTINCT 3 dates THEN 'Issue exists for 3 weeks in a row'
    FROM Merged;

我知道这不是正确的 SQL 格式,但有人知道如何编辑它吗?

每个 DMDUNIT 检查它是否在“问题”列中有 3 个问题,然后检查它是否有 3 个不同的开始日期。如果它有 3 个问题('Overforecasted'、“预测不足”)和同一个 DMDUNIT 的 3 个不同日期,我需要 return 它在一个新列中(以“3InARow”结尾)

当前编辑稿

 SET ARITHABORT OFF 
SET ANSI_WARNINGS OFF;


;WITH Forecast AS (
    SELECT LOC, DMDUNIT, STARTDATE, TOTFCST
    FROM SCPOMGR.FCSTPERFSTATIC
    WHERE STARTDATE >= '2021-11-24'
), Actuals AS (
    SELECT LOC, DMDUNIT, DMDPostDate, HistoryQuantity
    FROM SCPOMGR.HISTWIDE_CHAIN
    WHERE DMDPostDate >= '2021-11-24'

), Merged as (
    select
        COALESCE(f.LOC, a.LOC) AS LOC,
        COALESCE(f.DMDUNIT, a.DMDUNIT) AS DMDUNIT,
        COALESCE(f.STARTDATE, a.DMDPostDate) AS "Start Date",
        SUM(F.TOTFCST) AS "Forecast",
        SUM(a.HistoryQuantity) AS "Actuals",
        SUM(ABS(a.HistoryQuantity) - f.TOTFCST) AS "Abs Error",
        (1 - HistoryQuantity - TOTFCST) / HistoryQuantity as "FA%",
        SUM(a.HistoryQuantity) / SUM(f.TOTFCST) AS "Bias",       
        CASE
            WHEN TOTFCST > HistoryQuantity THEN 'Overforecasted' 
            WHEN TOTFCST < HistoryQuantity THEN 'Underforecasted'
            WHEN HistoryQuantity IS NULL AND TOTFCST > 0 THEN 'Overforecasted'
            WHEN TOTFCST IS NULL AND HistoryQuantity > 0 THEN 'Underforecasted'
            WHEN TOTFCST = 0.000 AND HistoryQuantity IS NULL THEN 'No issue'
        END AS Issue
    FROM Forecast f FULL OUTER JOIN Actuals a
        ON f.LOC = a.LOC AND f.DMDUNIT = a.DMDUNIT AND f.STARTDATE = a.DMDPostDate
         GROUP BY
        COALESCE(f.LOC, a.LOC),
        COALESCE(f.DMDUNIT, a.DMDUNIT),
        COALESCE(f.STARTDATE, a.DMDPostDate),
        a.HistoryQuantity, F.TOTFCST),
    Transitions as (
    select *, 
        case when indicator <> lag(indicator)
            over (partition by DMDUNIT order by "Start Date")
            then 1 end as tripped
    from Merged cross apply (
        select case when Issue in ('Overforecasted', 'Underforecasted') 
            then 1 else 0 end as indicator) v
), Bundles as (
    select *, count(tripped) over (partition by DMDUNIT order by "Start Date") as grp
    from Transitions
), Streaks as (
    select *, count(*) over (partition by DMDUNIT, grp) as cnt
    from Bundles
)
select *, case when indicator = 1 and cnt >= 3 then 'Yes' else 'No' end as InIssueStreak, cnt as StreakLength
from Streaks;

The fiddle

我创建了一个工作测试用例,它演示了如何识别连续几周超过或低于预测的项目。

关于如何计算每周价值或如何识别项目的所有细节对于基本问题都无关紧要。一周以来,我一直忽略与缺失数据相关的问题。这很容易包含在内,只是掩盖了所问的基本(也是唯一)问题。

对于这个例子,假设我们只有感兴趣的周,并且所有项目的所有周都存在。

SQL,其中还包含数据:

WITH forecast (item, prediction) AS (
        SELECT 1, 1000 UNION
        SELECT 2,  500
     )
   , actuals (weekno, item, actual) AS (
        SELECT  1, 1,  500 UNION
        SELECT  2, 1,  600 UNION
        SELECT  3, 1, 1600 UNION
        SELECT  4, 1, 1600 UNION
        SELECT  5, 1,  600 UNION
        SELECT  6, 1, 1100 UNION
        SELECT  7, 1, 1200 UNION
        SELECT  8, 1, 1150 UNION
        SELECT  9, 1,  601 UNION
        SELECT 10, 1,  602 UNION
        SELECT 11, 1,  603 UNION
        SELECT  1, 2, 1500 UNION
        SELECT  2, 2,  600 UNION
        SELECT  3, 2,  550 UNION
        SELECT  4, 2,  500 UNION
        SELECT  5, 2,  600 UNION
        SELECT  6, 2,  491 UNION
        SELECT  7, 2,  492 UNION
        SELECT  8, 2,  493 UNION
        SELECT  9, 2,  494 UNION
        SELECT 10, 2,  620
     )
   , step1 AS (
        SELECT a.*
             , f.prediction
             , CASE WHEN actual < prediction THEN -1
                    WHEN actual > prediction THEN +1
                    ELSE 0
               END AS side
          FROM forecast AS f
          JOIN actuals  AS a
            ON f.item = a.item
     )
   , step2 AS (
        SELECT *
             , CASE WHEN side = LAG(side) OVER (PARTITION BY item ORDER BY weekno) THEN 0 ELSE 1 END AS edge
          FROM step1
     )
   , step3 AS (
        SELECT *
             , SUM(edge) OVER (PARTITION BY item ORDER BY weekno) AS xgroup
          FROM step2
     )
   , step4 AS (
        SELECT *
             , COUNT(*) OVER (PARTITION BY item, xgroup) AS xcount
          FROM step3
     )
SELECT *
  FROM step4
 WHERE xcount >= 3
 ORDER BY item, weekno
;

结果:

weekno item actual prediction side edge xgroup xcount
6 1 1100 1000 1 1 4 3
7 1 1200 1000 1 0 4 3
8 1 1150 1000 1 0 4 3
9 1 601 1000 -1 1 5 3
10 1 602 1000 -1 0 5 3
11 1 603 1000 -1 0 5 3
1 2 1500 500 1 1 1 3
2 2 600 500 1 0 1 3
3 2 550 500 1 0 1 3
6 2 491 500 -1 1 4 4
7 2 492 500 -1 0 4 4
8 2 493 500 -1 0 4 4
9 2 494 500 -1 0 4 4
WITH Forecast AS (
    SELECT LOC, DMDUNIT, STARTDATE, TOTFCST
    FROM SCPOMGR.FCSTPERFSTATIC
    WHERE STARTDATE >= '2021-11-24'
), Actuals AS (
    SELECT LOC, DMDUNIT, DMDPostDate, HistoryQuantity
    FROM SCPOMGR.HISTWIDE_CHAIN
    WHERE DMDPostDate >= '2021-11-24'
), Merged AS (
    SELECT
        COALESCE(f.LOC, a.LOC) AS LOC,
        COALESCE(f.DMDUNIT, a.DMDUNIT) AS DMDUNIT,
        COALESCE(f.STARTDATE, a.DMDPostDate) AS "Start Date",
        SUM(F.TOTFCST) AS "Forecast",
        SUM(a.HistoryQuantity) AS "Actuals",
        SUM(ABS(a.HistoryQuantity) - f.TOTFCST) AS "Abs Error"
        (1 - SUM(a.HistoryQuantity - SUM(f.TOTFCST)) / SUM(a.HistoryQuantity) as "FA%",
        SUM(a.HistoryQuantity) / SUM(f.TOTFCST) AS "Bias",
        CASE
            WHEN SUM(f.TOTFCST) > SUM(a.HistoryQuantity) THEN 'Overforecasted' 
            WHEN SUM(f.TOTFCST) < SUM(a.HistoryQuantity) THEN 'Underforecasted'
            WHEN SUM(a.HistoryQuantity) IS NULL AND SUM(f.TOTFCST) > 0 THEN 'Overforecasted'
            WHEN SUM(f.TOTFCST) IS NULL AND SUM(a.HistoryQuantity) > 0 THEN 'Underforecasted'
            WHEN SUM(f.TOTFCST) = 0.000 AND SUM(a.HistoryQuantity) IS NULL THEN 'No issue'
        END AS Issue
    FROM Forecast f FULL OUTER JOIN Actuals a
        ON f.LOC = a.LOC AND f.DMDUNIT = a.DMDUNIT AND f.STARTDATE = a.DMDPostDate
    GROUP BY
        COALESCE(f.LOC, a.LOC),
        COALESCE(f.DMDUNIT, a.DMDUNIT),
        COALESCE(f.STARTDATE, a.DMDPostDate)
    ORDER BY
        COALESCE(f.LOC, a.LOC),
        COALESCE(f.DMDUNIT, a.DMDUNIT),
        COALESCE(f.STARTDATE, a.DMDPostDate)
)
select *,
    case when
        min(Issue) over (
            partition by DMDUNIT order by "Start Date"
            rows between 2 preceding and current row) =
        max(Issue) over (
            partition by DMDUNIT order by "Start Date"
            rows between 2 preceding and current row) and
        count(Issue) over (
            partition by DMDUNIT order by "Start Date"
            rows between 2 preceding and current row) = 3
        then 'Yes' else 'No' end as "3InARow"
from Merged;

如果这不起作用,请尝试间隙和孤岛:

with (<copied from above...>), Transitions as (
    select *, 
        case when indicator <> lag(indicator)
            over (partition by DMDINIT order by "Start Date")
            then 1 end as tripped
    from Merged cross apply (
        select case when Issue in ('Overforecasted', 'Underforecasted') 
            then 1 else 0 end as indicator) v
), Bundles as (
    select *, sum(tripped) over (partition by DMDUNIT order by "Start Date") as grp
    from Transitions
), Streaks as (
    select *, count(*) over (partition by DMDUNIT, grp) as cnt
    from Bundles
)
select *, case when cnt >= 3 then 'Yes' else 'No' end as InStreak, cnt as StreakLength
from Streaks;

https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=9fcbab1d93b7297aebc340111aa3a448