【问题标题】:How to build a rolling forward SSRS report如何构建前滚 SSRS 报告
【发布时间】:2017-01-22 21:31:19
【问题描述】:

我一直在编写一份报告,允许用户查看向前滚动的总数。

这是一个矩阵。我已经包含了一个关于数据外观的示例。

报告应该从 10 月开始计算总计,金额为 42 美元。然后报告将汇总帐户。然后取 42 美元 + 64 美元 = 106 美元。 106 美元将结转到 12 月份,从 106 美元的期初余额开始。

报告我正在处理

报告示例

                     2016-011            2016-012

Beginning Balance       42                   106

AP                      31                    41
APAJ                    32                    42
CJ                      33                    43
GEN                    -32                   -42

Total Account           64                    84

Begin Bal + Total Acc  106                   190

数据示例

DECLARE @ClosingBalTemp TABLE
(
  Account_ID varchar(30),
  Period_Nbr varchar(10),
  Source_Code varchar(10),
  Closing_Balance_Amt numeric(16,2)
)

INSERT INTO @ClosingBalTemp (Account_ID, Period_Nbr, Source_Code, Closing_Balance_Amt)

    VALUES ('01-002-333', '2016-008', 'AP', 1),
           ('01-002-333', '2016-008', 'APAJ', 2),
           ('01-002-333', '2016-008', 'CJ', 3),
           ('01-002-333', '2016-008', 'GEN', -2),
           ('01-002-333', '2016-009', 'AP', 11),
           ('01-002-333', '2016-009', 'APAJ', 12),
           ('01-002-333', '2016-009', 'CJ', 13),
           ('01-002-333', '2016-009', 'GEN', -12),
           ('01-002-333', '2016-010', 'AP', 20),
           ('01-002-333', '2016-010', 'APAJ', 21),
           ('01-002-333', '2016-010', 'CJ', 23),
           ('01-002-333', '2016-010', 'GEN', -22),
           ('01-002-333', '2016-011', 'AP', 31),
           ('01-002-333', '2016-011', 'APAJ', 32),
           ('01-002-333', '2016-011', 'CJ', 33),
           ('01-002-333', '2016-011', 'GEN', -32),
           ('01-002-333', '2016-012', 'AP', 41),
           ('01-002-333', '2016-012', 'APAJ', 42),
           ('01-002-333', '2016-012', 'CJ', 43),
           ('01-002-333', '2016-012', 'GEN', -42)

SELECT * FROM @ClosingBalTemp


The data should look like this

The logic is almost working. The Bal type is not calculating the running balance correctly after Period 9. The 4.00 is coming from Oct that does not display.

B   BAL    2016 9   4.00
T   AP     2016 9   11.00
T   APAJ   2016 9   12.00
T   CJ     2016 9   13.00
T   GEN    2016 9   -12.00
B   BAL    2016 10  24.00     **Should be 33**
T   AP     2016 10  20.00
T   APAJ   2016 10  21.00
T   CJ     2016 10  23.00
T   GEN    2016 10  -22.00
B   BAL    2016 11  42.00     **Should be 75**
T   AP     2016 11  31.00
T   APAJ   2016 11  32.00
T   CJ     2016 11  33.00
T   GEN    2016 11  -32.00
B   BAL    2016 12  64.00     **Should be 139**
T   AP     2016 12  41.00
T   APAJ   2016 12  42.00
T   CJ     2016 12  43.00
T   GEN    2016 12  -42.00

【问题讨论】:

    标签: sql-server reporting-services ssrs-2008


    【解决方案1】:

    由于列布局,我认为运行总计不会起作用。我们希望 2016-012 的顶部来自 2016-011 的底部。我会说我不太了解您的数据集,并且我做了很多前滚/试算表Hers's s post on Trial blances。但我相信我已经通过建议的存储过程使用 2008 年的东西解决了您的问题。理想情况下,年份和期间将是单独的字段,以便更轻松地计算期间。我现在只是对它们进行硬编码。 通过输出,您可以在 SSRS 报告中为每个月创建一个列。您可以在 SSRS 中自己计算月末总计。 在 2008 年可能有更好的方法来做到这一点,但我的服务器上没有 2008,所以我无法测试。 (我会以不同的方式处理期初余额汇总)

    DECLARE @CurrentPeriod CHAR(10);
    DECLARE @PriorPeriod CHAR(10);
    DECLARE @PPPeriod CHAR(10)
    
    SET @CurrentPeriod = '2016-012';
    SET @PriorPeriod = '2016-011';
    SET @PPPeriod = '2016-010';
    -- First Step - Summarize the balances
    WITH Balances (CurrentPeriodOpenBal, PriorPeriodOpenBal)
      AS (
         SELECT SUM(CASE WHEN cbt.Period_Nbr IN (@PPPeriod, @PriorPeriod)
                THEN cbt.Closing_Balance_Amt ELSE 0 END)
                AS CurrentPeriodOpenBal,
            SUM(CASE WHEN cbt.Period_Nbr IN (@PPPeriod) 
                THEN cbt.Closing_Balance_Amt ELSE 0 END) 
                AS PriorPeriodOpenBal
            FROM dbo.ClosingBalTemp cbt
            WHERE cbt.Period_Nbr < @CurrentPeriod
      )
    -- Now we are going to combine our balances and our transaction
    ,
    BalTrans (TransType, SourceCode, PeriodNbr, Amount) AS
    (
    SELECT 'B', 'BAL', @PriorPeriod, bal.PriorPeriodOpenBal 
    FROM Balances bal   
    UNION ALL 
    SELECT 'B', 'BAL', @CurrentPeriod, bal.CurrentPeriodOpenBal 
    FROM Balances  bal
    UNION ALL  
    SELECT 'T', trans.Source_Code, trans.Period_Nbr,  trans.Closing_Balance_Amt
       FROM dbo.ClosingBalTemp trans
      WHERE trans.Period_Nbr BETWEEN @PriorPeriod AND @CurrentPeriod
    )
    -- Now we simply order our transactions   
    SELECT bt.TransType, bt.SourceCode, bt.PeriodNbr, bt.Amount FROM BalTrans bt
     ORDER BY bt.PeriodNbr, bt.TransType, bt.SourceCode
    

    --- 修订版

    -- First Step - convert period to fiscla year and period
    WITH Trans AS
      (SELECT cbt.Account_ID, 
        cbt.Period_Nbr,
        CAST(SUBSTRING(cbt.Period_Nbr,1,4) AS INT) AS FiscalYear,
        CAST(SUBSTRING(cbt.Period_Nbr,6,3) AS INT) AS FiscalPeriod,
        cbt.Source_Code,
        cbt.Closing_Balance_Amt
        FROM dbo.ClosingBalTemp cbt) 
    
    
    -- This gets the total balance for each period - we add one to the period
    -- to figure out the opening info
    , Balances ( FiscalYear, FiscalPeriod, OpenPeriod, Amount)
     AS (
      SELECT DISTINCT
           bal.FiscalYear,
           bal.FiscalPeriod,
           bal.FiscalPeriod + 1 AS OpenPeriod,
           SUM(bal.Closing_Balance_Amt) OVER(ORDER BY bal.Period_Nbr) AS Amount  
            FROM Trans bal
            WHERE bal.Period_Nbr >= @PPPeriod 
              AND bal.Period_Nbr  < @StartingPeriod
      )
    -- Now we are going to combine our balances and our transaction
    ,
    
    BalTrans (TransType, SourceCode, FiscalYear, FiscalPeriod, Amount) AS
    (
     SELECT 'B', 'BAL', bl.FiscalYear, bl.OpenPeriod, bl.Amount FROM Balances bl    
    UNION ALL 
    SELECT 'T', trans.Source_Code, trans.FiscalYear, trans.FiscalPeriod, 
            trans.Closing_Balance_Amt
    FROM Trans trans
    WHERE trans.Period_Nbr BETWEEN @EndingPeriod AND @StartingPeriod
    )   
    SELECT bt.TransType, bt.SourceCode, bt.FiscalYear, Bt.FiscalPeriod,
     bt.Amount FROM BalTrans bt
    ORDER BY bt.FiscalYear, bt.FiscalPeriod, bt.TransType, bt.SourceCode
    

    -- 光标示例

    DECLARE @EndPeriod CHAR(10);
    DECLARE @StartPeriod CHAR(10);
    DECLARE @PPPeriod CHAR(10)
    -- Ideally, year and period would be separate integer fields
    -- so one could calculate prior period from current Period.
    -- But that's not the key part of the question 
    SET @EndPeriod = '2016-012';
    SET @StartPeriod = '2016-009';
    SET @PPPeriod = '2016-008';
    
    DECLARE @Period_Nbr CHAR(10);
    DECLARE @Source_Code CHAR(10);
    DECLARE @Closing_Balance_Amt NUMERIC(16,2);
    
    DECLARE @ReportPeriod CHAR(10);
    DECLARE @ReportBalance NUMERIC(16,2);
    
    CREATE TABLE #Output 
    ( ID INTEGER IDENTITY (1,1) PRIMARY KEY,   
      Period_Nbr CHAR(10), 
      Source_Code CHAR(10),
      Closing_Balance_Amt numeric(10,2)
      )
      -- the following insures that SSRS sees the output correctly
    IF 1=2
      BEGIN
         SELECT ID,
            Period_Nbr,
            Source_Code,
            Closing_Balance_Amt
            FROM #Output;
      END;
    
    DECLARE OMGUAC CURSOR FAST_FORWARD FOR
      SELECT Period_Nbr, Source_Code, Closing_Balance_Amt
      FROM dbo.ClosingBalTemp
      WHERE Period_Nbr BETWEEN @PPPeriod AND @EndPeriod
      ORDER BY Period_Nbr, Source_Code;
    
    OPEN OMGUAC;
    
    FETCH NEXT FROM OMGUAC INTO @Period_Nbr,@Source_Code,@Closing_Balance_Amt;
    
    SET @ReportPeriod = @Period_Nbr;
    SET @ReportBalance = 0;
    
    WHILE @@FETCH_STATUS = 0
      BEGIN 
        -- When the period Changes, print the opening balance
         IF @Period_Nbr <> @ReportPeriod    
            BEGIN 
                INSERT INTO #Output
                    ( Period_Nbr ,
                      Source_Code ,
                      Closing_Balance_Amt
                    )
                VALUES  (@Period_Nbr, 'Open Bal',@ReportBalance);
            END
     IF @Period_Nbr > @PPPeriod
        BEGIN 
            INSERT INTO #Output
                    ( Period_Nbr ,
                      Source_Code ,
                      Closing_Balance_Amt
                    )
            VALUES  (@Period_Nbr, @Source_Code,@Closing_Balance_Amt);
        END
      SET @ReportBalance = @ReportBalance + @Closing_Balance_Amt;
      SET @ReportPeriod = @Period_Nbr
      FETCH NEXT FROM OMGUAC INTO @Period_Nbr, @Source_Code,
     @Closing_Balance_Amt;
       END;
    SELECT * FROM #Output 
    ORDER BY ID;
    DROP TABLE #Output;
    CLOSE OMGUAC;
    DEALLOCATE OMGUAC;
    

    【讨论】:

    • 嗨亚当,哇!谢谢你的帮助。这太好了……我有一个小问题。如果您在上一期间输入 2016-009,在上一期间输入 2016-008,在当前期间输入 2016-012,则 BAL 不会计算 2016-010 或 2016-011。它不计算所选期间范围内的期间。该报告应适用于输入的任何期间范围。
    • 首先,请您接受我的回答。谢谢。接下来,您的问题没有具体说明您将如何进行选择 - 多少个时期,如何回答,所以我从输出中假设您选择了两个月。指定你想象的选项(和列),答案应该很容易调整
    • 嗨,亚当,很抱歉。是的,我没有解释如何选择数据。在日期范围 08/01/16 - 12/31/16 上选择数据。我将 2 个日期转换为开始和结束期间。然后基于期间的数量将是除上一个上一个期间之外的列标题。我只从那个时期获得起始余额。之后,每个时期的总和将成为下一个时期的期初余额。这将一直发生,直到显示所有期间。
    • 在第一次将您的会计年度和期间分成两个字段之后,我添加了另一组代码。您可以进行编辑以恢复原状。
    • 嗨,亚当,感谢您的快速回复。 :看起来 SQL 2008 不支持 OVER()。 dba.stackexchange.com/questions/47116/….
    【解决方案2】:

    在这里查看 runningvalue():https://msdn.microsoft.com/en-us/library/dd255229.aspx 这可以与一个组一起用作范围,因此可以用于您的列组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      • 1970-01-01
      • 1970-01-01
      • 2015-10-08
      • 1970-01-01
      相关资源
      最近更新 更多