【问题标题】:SQL Server: Sum of Calculated Row within N MonthsSQL Server:N 个月内计算行的总和
【发布时间】:2016-12-27 18:46:46
【问题描述】:

我是 SQL Server 的新手,并且有一个关于使用条件语句对计算行求和的问题。

我的数据组织如下:

ID  S_DATE     END_DATE   MNum  CHG  DateCHG
---------------------------------------------
1   1/26/2001   2/26/2001   7   NULL   1
1   2/27/2001   3/27/2001   8   1      1
1   3/28/2001   1/9/2003    9   1      21
1   1/10/2003   3/2/2004    11  2      14
1   3/3/2004    10/14/2004  10  -1     7
1   10/15/2004  6/22/2005   9   -1     8
1   6/23/2005   3/9/2008    8   -1    33
1   3/10/2008   1899-12-30  0   NULL    -1299
2   9/23/1993   9/11/2000   3   NULL    84
2   1/1/1999    12/31/1998  3   0   -1
2   9/12/2000   11/13/2001  2   -1  14
2   11/14/2001  1899-12-30  0   NULL    -1223

DateCHG 等于 S_DATE 和 End_Date 之间的月数。我想找到在前一个日期的 3 个月内出现 CHG 的每个 ID 的 CHG 总和。

这是我当前的代码(注意:出于格式化目的,列标题与上面的数据不同。我也无法写入此数据库,因此只能以查询格式写入)

SELECT
     *,  
     CASE 
        WHEN MratingNum = 0 OR
             LAG(MratingNum) OVER (OVER BY MAST_ISSU_NUM, RATG_DATETIME) = 0 OR 
             MAST_ISSU_NUM <> LAG(MAST_ISSU_NUM) OVER (ORDER BY MAST_ISSU_NUM, RATG_DATETIME) --OR
            --LAG(MratingNum) OVER (ORDER BY MAST_ISSU_NUM, RATG_DATETIME) < 12 OR  --By Credit Rating
            --LAG(MratingNum) OVER (ORDER BY MAST_ISSU_NUM, RATG_DATETIME) < 18
           THEN NULL 
           ELSE CAST(MratingNum AS INT) - LAG(MratingNum) OVER (ORDER BY MAST_ISSU_NUM, RATG_DATETIME)
    END AS CHG,
    DATEDIFF(month, RATG_DATETIME, RATG_END_DATETIME) AS DateCHG 
FROM
    MOODYS_DRD.dbo.DEBT_RATG AS t1
LEFT JOIN
    sandbox.dbo.RatingMap AS t2 ON t1.RATG_TXT = t2.MratingValue
WHERE 
    RATG_TYP_CD = 'LT'
ORDER BY 
    MAST_ISSU_NUM, RATG_DATETIME

例如,输出将如下所示:

ID S_DATE   .... SumCHG
1  1/26/2001....   NULL
1  2/27/2001....   NULL
1  3/28/2001....   2
1  1/10/2003....   NULL
1  3/3/2004 ....   NULL

我假设最好的方法是计算 DateCHG 小于 3 的滚动总和,然后对 CHG 列求和?谢谢大家!

编辑:这相当复杂,所以让我尝试另一种提问方式。对于每条记录,我想在 S_DATE 的 3 个月内回顾并找到 CHG 的总和。对于 2001 年 3 月 28 日,这将包括 2/01 和 1/01。 MNum 从 7 变为 9,因此 CHG 的 SUM 为 2。但是从 3/04 开始,过去 3 个月没有变化,因此返回 NULL。我显然想按 ID 执行此操作,因此不想将 ID 2 到 1 的 3 个月重叠。希望现在这更有意义吗?

【问题讨论】:

  • 您的输出示例如何是您所要求的?您要求每个 ID 的 SumChg 总数,因此您只会返回一次 ID =1。
  • @Edward 按每个 ID 表示我不想在 ID 之间重叠。我想查看每一行,找出前 3 个月内所有内容的总和。如果每个 ID 只有 2 行并且相隔 6 个月,我想返回 NULL。如果一个 ID 有 20 行,并且在 3 个月内有 2 个“数据块”,我想找到每个数据块的总和。希望这是有道理的?
  • 并非如此。你说的丛是什么意思?通过重叠,我认为您的意思是您不想将 ID=1 与 ID=2 混合。请检查我的答案,并从那里告诉我你想要完成的事情是什么......

标签: sql-server


【解决方案1】:

t0t 用于设置数据。

with    t0
          as ( select   *
               from     ( values ( 1, '1/26/2001', '2/26/2001', 7, null, 1),
                        ( 1, '2/27/2001', '3/27/2001', 8, 1, 1),
                        ( 1, '3/28/2001', '1/9/2003', 9, 1, 21),
                        ( 1, '1/10/2003', '3/2/2004', 11, 2, 14),
                        ( 1, '3/3/2004', '10/14/2004', 10, -1, 7),
                        ( 1, '10/15/2004', '6/22/2005', 9, -1, 8),
                        ( 1, '6/23/2005', '3/9/2008', 8, -1, 33),
                        ( 1, '3/10/2008', '1899-12-30', 0, null, -1299),
                        ( 2, '9/23/1993', '9/11/2000', 3, null, 84),
                        ( 2, '1/1/1999', '12/31/1998', 3, 0, -1),
                        ( 2, '9/12/2000', '11/13/2001', 2, -1, 14),
                        ( 2, '11/14/2001', '1899-12-30', 0, null, -1223) ) t ( ID, S_DATE, END_DATE, MNum, CHG, DateCHG )
             ),
        t as ( select   t0.ID ,
                        cast(t0.S_DATE as date) S_DATE ,
                        cast(t0.END_DATE as date) END_DATE ,
                        t0.MNum ,
                        t0.CHG ,
                        t0.DateCHG
               from     t0
             )
    select  case when Cnt >= 3 then p.CHG
            end SumCHG,
            *
    from    t
            outer apply ( select    sum(u.CHG) CHG ,
                                    count(*) Cnt
                          from      t u
                          where     u.ID = t.ID
                                    and u.S_DATE between dateadd(month, -3,
                                                              t.S_DATE)
                                                 and     t.S_DATE
                        ) p
    order by t.ID ,
        t.S_DATE;

为您的表格使用 CTE,

;with t as (
SELECT
     *,  
     CASE 
        WHEN MratingNum = 0 OR
             LAG(MratingNum) OVER (OVER BY MAST_ISSU_NUM, RATG_DATETIME) = 0 OR 
             MAST_ISSU_NUM <> LAG(MAST_ISSU_NUM) OVER (ORDER BY MAST_ISSU_NUM, RATG_DATETIME) --OR
            --LAG(MratingNum) OVER (ORDER BY MAST_ISSU_NUM, RATG_DATETIME) < 12 OR  --By Credit Rating
            --LAG(MratingNum) OVER (ORDER BY MAST_ISSU_NUM, RATG_DATETIME) < 18
           THEN NULL 
           ELSE CAST(MratingNum AS INT) - LAG(MratingNum) OVER (ORDER BY MAST_ISSU_NUM, RATG_DATETIME)
    END AS CHG,
    DATEDIFF(month, RATG_DATETIME, RATG_END_DATETIME) AS DateCHG 
FROM
    MOODYS_DRD.dbo.DEBT_RATG AS t1
LEFT JOIN
    sandbox.dbo.RatingMap AS t2 ON t1.RATG_TXT = t2.MratingValue
WHERE 
    RATG_TYP_CD = 'LT'
)
    select  case when Cnt >= 3 then p.CHG
            end SumCHG,
            *
    from    t
            outer apply ( select    sum(u.CHG) CHG ,
                                    count(*) Cnt
                          from      t u
                          where     u.ID = t.ID
                                    and u.S_DATE between dateadd(month, -3,
                                                              t.S_DATE)
                                                 and     t.S_DATE
                        ) p
    order by t.ID ,
        t.S_DATE;

【讨论】:

  • 我觉得这是在正确的道路上,但我不确定如何合并到我现有的代码中?我对 SQL 还是很陌生,不确定语法属于哪里...
  • select 部分开始。将t 更改为yourDataSource t
  • 顺便说一句,你叫什么名字?
  • 无效的对象名称 'u' - 尝试一堆迭代,看看哪个有效。 CHG 字段是从另一个 SELECT 计算出来的,我不确定我是否正确调整了它。在任何情况下,您都可以通过 gmail 的 nyobna 给我发电子邮件,询问姓名,显然不想在开放论坛中分享:)
  • 对于from t u,只需将t 更改为您的数据源即可。
猜你喜欢
  • 2021-07-17
  • 1970-01-01
  • 2016-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-09
相关资源
最近更新 更多