如何在报告的同一时期显示实际情况和预测而不会变得愚蠢?

时间:2012-09-12 15:51:50

标签: sql sql-server reporting ssas

所以我有一个系统,用户可以预测到一个月结束后的第18天。但是,在这个月里他们每天都会输入实际值。

所以说当前的日期是2012年9月12日。我预测本月有100个单位,而且我已经有25个单位的实际数据。

由于尚未达到10月18日,我将报告9月的预测数字为100个单位。但是,用户还希望能够看到他们迄今为止输入的25个单位。

我的报告中有两项措施,一项针对“实际”,另一项针对“预测”。如果我允许9月的实际值出现在报告中,那么我将显示125个单位的数字,这显然是不正确的,并且会使我的年度总数也不正确。

我考虑添加一个新措施“Transient Actuals”,它只会在当月使用而不会累积,但这似乎很疯狂!

我认为技术根本不重要,但我使用的是SQL Server数据库,而报告是Analysis Services多维数据集。

当然这一定是个常见问题?


好的 - 我确实有一个架构,但它非常非常复杂,报表和数据库表之间有多层。但是,我可以给你一个简单的SQL示例。

--Actuals and Forecast Tables
DECLARE @Actuals TABLE (
    [Month] INT,
    Value NUMERIC(19,2));
DECLARE @Forecast TABLE (
    [Month] INT,
    Value NUMERIC(19,2));

--Pretending we are in Month #3 put in some dummy data
INSERT INTO @Actuals VALUES (1, 100);
INSERT INTO @Actuals VALUES (2, 120);
INSERT INTO @Actuals VALUES (3, 10);
INSERT INTO @Forecast VALUES (1, 90);
INSERT INTO @Forecast VALUES (2, 90);
INSERT INTO @Forecast VALUES (3, 90);

--Calculate the latest actuals period (this would usually be time-based)
DECLARE @LatestActualsPeriod INT = 2;

--Now report the data to the user
SELECT
    [Month],
    'Actuals' AS Source,
    Value
FROM
    @Actuals
WHERE
    [Month] <= @LatestActualsPeriod
UNION ALL
SELECT
    [Month],
    'Forecast',
    Value
FROM
    @Forecast
WHERE
    [Month] > @LatestActualsPeriod;

现在结果将是一个包含以下数据的表:

Month    Source    Value
1        Actuals   100.00
2        Actuals   120.00
3        Forecast   90.00

那么我在哪里将10.00实际值放在第3个月而不会使总数不正确并且仍然显示某个月的某个月的预测?


好的,感谢Jeremy我觉得我有答案......问题是我的报告中有这样的数据:

Row Labels  Actual   Forecast Total
2012    23.840  18.840  42.680
2012/Jan    3.580   0.000   3.580
2012/Feb    3.520   0.000   3.520
2012/Mar    4.000   0.000   4.000
2012/Apr    3.350   0.000   3.350
2012/May    3.440   0.000   3.440
2012/Jun    3.090   0.000   3.090
2012/Jul    2.860   0.000   2.860
2012/Aug    0.000   4.990   4.990
2012/Sep    0.000   3.500   3.500
2012/Oct    0.000   4.130   4.130
2012/Nov    0.000   2.710   2.710
2012/Dec    0.000   3.510   3.510
Grand Total 23.840  18.840  42.680

这是一个Analysis Services多维数据集,因此我无法显示“90 Actual / 10 Forecast”,每个单元格必须包含一个数字。但是,我有另一个解决方案。如果我添加一个包含两个成员的新维度,我可以使用它来控制显示的内容。

所以新维度将有两个选择,“全部显示”或“显示相关”(我可能需要处理名称)。如果用户选择了“显示全部”成员,则他们将看到系统保留的任何实际值和预测值。因此,这意味着它们的总数将毫无意义,因为它将包括截至目前月份的预测和实际数据以及未来几个月的预测。

但是,如果用户选择“显示相关”成员,那么他们只会看到尚未完成的月份的实际值和未来月份的预测(如上所示)。

这意味着每个报告都需要包含这个维度并强制用户选择其中一个成员,否则他们的数字将毫无意义,因此它不是最优雅的解决方案。

1 个答案:

答案 0 :(得分:0)

我在这里做了一堆假设,但希望这在这里很有用。我接受了您的询问并向您展示了其他一些方法,我认为如果我能正确理解问题,我认为可以帮助您以更易于阅读的方式显示数据。

在第一个例子中,我假设你总是将日期作为月份的第一天。如果没有,那么它可能会变得有点棘手,或者您可以使用DATEPART(MONTH, ...使其工作方式类似于将其存储为INT。我不是假设每个月都有预测值或实际价值。

在第二个例子中,为了方便起见,我假设你只想用实际值显示最近一个月的实际值。然后我假设你想要那个月及以后的预测值和实际值(如果有的话)。我还假设在第二个查询中每个月都有一个预测值。

如果这些假设中的任何一个不正确,那么可以进一步修改查询以处理该问题。

--Actuals and Forecast Tables
DECLARE @Actuals TABLE (
    [Month] DATE,
    Value NUMERIC(19,2));
DECLARE @Forecast TABLE (
    [Month] DATE,
    Value NUMERIC(19,2));

INSERT INTO @Actuals VALUES ('20120801', 100);
INSERT INTO @Actuals VALUES ('20120901', 120);
INSERT INTO @Actuals VALUES ('20121001', 10);
INSERT INTO @Forecast VALUES ('20120801', 90);
INSERT INTO @Forecast VALUES ('20120901', 90);
INSERT INTO @Forecast VALUES ('20121001', 90);

INSERT INTO @Actuals VALUES ('20121101', 50);
INSERT INTO @Forecast VALUES ('20121201', 90);
-- If you can't have an actuals record without a forcast record, remove all the ISNULL'ing except the first ISNULL on the [Actual/Forecast] line
-- and change to LEFT JOIN instead of FULL.
SELECT
    SUBSTRING(CONVERT(VARCHAR, ISNULL(F.[Month], A.[Month]), 103), 4, 999) [Report Month]
    , ISNULL(CAST(A.Value AS VARCHAR(20)), '-') + '/' + ISNULL(CAST(F.Value AS VARCHAR(20)), '-') [Actual/Forecast]
FROM
    @Forecast F
    FULL JOIN @Actuals A
        ON A.[Month] = F.[Month]
ORDER BY
    [Report Month]

DELETE @Actuals
WHERE [Month] = '20121101'
DELETE @Forecast
WHERE [Month] = '20121201'

DECLARE @LatestActualsPeriod DATE = (SELECT MAX([Month]) FROM @Actuals);

SELECT
    [Month] [Report Month]
    , CAST(A.Value AS VARCHAR(20)) + ' Actual' [Units]
FROM
    @Actuals A
WHERE
    A.[Month] < @LatestActualsPeriod

UNION

SELECT
    F.[Month] [Report Month]
    , ISNULL(CAST(A.Value AS VARCHAR(20)), '-') + '/' + CAST(F.Value AS VARCHAR(20)) + ' Actual/Forecasted'
FROM
    @Forecast F
    LEFT JOIN @Actuals A
        ON A.[Month] = F.[Month]
WHERE
    F.[Month] >= @LatestActualsPeriod

P.S。:你在答案中加了一个架构,但没有回复我的评论要求它。如果我出于好奇而没有再回头看这个问题,我就不会知道你编辑了你的问题。