【问题标题】:How to design bar chart on SSRS如何在 SSRS 上设计条形图
【发布时间】:2017-05-05 12:57:49
【问题描述】:

我想创建如下图关于 SSRS 的报告。

黄色部分表示SET_PHASE, 绿色部分表示PROD_PHASE

而我的查询结果是这样的:

我想为每行、所有订单显示,我想为每个订单显示,SETUP 和 PRODUCTION 取决于持续时间。

SET_PHASE的持续时间是SET_DURATION

PROD_PHASE的持续时间是PROD_DURATION

我希望我的问题很清楚 :) 你能帮我解决问题吗?


答案:

你好艾伦,

目前的情况我只有这些数据:

PROD100059335   SETUP   PRODUCTION  1   14  LINE 4
PROD100058991   SETUP   PRODUCTION  1   5   LINE 6
PROD100059259   SETUP   PRODUCTION  2   24  LINE 4
PROD100059188   SETUP   PRODUCTION  1   3   LINE 2
PROD100059248   SETUP   PRODUCTION  1   15  LINE 2
PROD100059055   SETUP   PRODUCTION  2   23  LINE 2
PROD100058754   SETUP   PRODUCTION  5   18  LINE 6

如果我使用您的查询,我只会显示“PROD100058754”、“PROD100059259”、“PROD100059055”这些顺序。我不明白为什么其他数据会丢失。

直到 "DECLARE @n TABLE(n int)" 部分我可以显示其他数据。但在那之后我就不能显示了。

我在 SSRS 上应用了程序,我的报告显示如下:

我做错了,我不知道如何解决它们:(

例如“PROD100059259”这个订单通常有设置阶段,但在报告中我没有黄色字段。

你对我有什么建议吗?

【问题讨论】:

  • 这是可能的(可能!)。我自己也建立了类似的东西。我可以看到您面临的问题是数据的规模。我们必须建立一个矩阵报告,每列代表固定的时间量。查看您的样本数据,并假设数据以分钟/秒或小时/分钟为单位,则 PROD100057968 的设置时间为 1 分钟,生产时间为 192 小时,是 11000 倍。要么在报表上丢失设置时间,要么报表需要数万列,这是不可行的。
  • 接下来,您可以通过缩放所有内容来妥协,使其适合 256 列(SSRS 矩阵最大值),但它不准确。如果这听起来不错,请告诉我,我会看看能不能把东西放在一起
  • 您好,感谢您的回答。我尝试使用堆叠条。也许我可以使用堆叠条,但我仍然有一些问题。我的值 1 是 SET_PHASE,值 2 是 PROD_PHASE。类别组是 LINE 并且系列组是 STR_ORDER_ID 但是如果我创建这样我就不能使用持续时间,我不知道如何为每个订单更改颜色绿色和黄色,我应该在每个不同的订单上放置间隙。你能帮我解决这些问题吗?而且我不知道通过这种方式(堆叠条)是否有意义?
  • 同样,这是可能的,但您会遇到同样的问题。当您的设置时间短而生产时间长时,设置时间将如此之短,以至于您根本看不到它。我会看看我能不能想出一些东西来以合理的格式获取数据,然后你可以从那里选择你想用它做什么。
  • [在此处输入图片描述][1] [1]:i.stack.imgur.com/7Msri.png

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


【解决方案1】:

好的,这里试图给你你想要的,但有一些警告:

  1. 持续时间是按比例缩放的,任何操作都不能少于 1 个时间段,因此设置与生产持续时间只是近似值
  2. 我还没有找到标记每个条的好方法,所以我使用了工具提示

首先是代码...我已经添加了很多 cmets,所以希望你能一直遵循它,它基于你的示例数据。

注意:我已经更新了表格,因为现在看起来您使用的是整数持续时间,而不是第一个示例中的 00:00 格式。

-- CREATE A TEST TABLE AND POPULATE IT
DECLARE @data TABLE(STR_ORDER_ID varchar(20), SET_DURATION varchar(10), PROD_DURATION varchar(10), Set_decimal int, Prod_Decimal int, Line varchar(10))

INSERT INTO @data
VALUES
('PROD100059335', NULL, NULL, 1, 14, 'LINE 4'),
('PROD100058991', NULL, NULL,1, 5, 'LINE 6'),
('PROD100059259', NULL, NULL,2, 24, 'LINE 4'),
('PROD100059188', NULL, NULL,1, 3, 'LINE 2'),
('PROD100059248', NULL, NULL,1, 15, 'LINE 2'),
('PROD100059055', NULL, NULL,2, 23, 'LINE 2'),
('PROD100058754', NULL, NULL,5, 18, 'LINE 6')

DECLARE @Gap int = 2 -- determines how many columns we use to separate each order

-- ASSUME durations are in hours/minutes or minutes/seconds and convert them to decimal minutes or decimal seconds respectively

-- COMMENTED THIS AS WE NO LONGER NEED IT. No longer required as durations are now integer values.
--UPDATE d 
--    SET 
--        Set_decimal = (CAST(LEFT(d.SET_DURATION, len(d.SET_DURATION)-3) AS INT) * 60) +  CAST(RIGHT(d.SET_DURATION, 2) AS INT)  ,
--        Prod_Decimal = (CAST(LEFT(d.PROD_DURATION, len(d.PROD_DURATION)-3) AS INT) * 60) +  CAST(RIGHT(d.PROD_DURATION, 2) AS INT) 
--FROM @data d


-- CREATE A NORMALISED TABLE, this will just help to make the next steps simpler
DECLARE @normData TABLE(RowId INT IDENTITY (1,1), Line varchar(10), STR_ORDER_ID varchar(20), OperationOrder int, Operation varchar(10), Duration int)
INSERT INTO @normData (Line, STR_ORDER_ID, OperationOrder, Operation, Duration)
SELECT * FROM (
SELECT Line, STR_ORDER_ID, 1 as OperationOrder , 'SET' as Operation , Set_decimal FROM @data 
UNION
SELECT Line, STR_ORDER_ID, 2 , 'PROD' , Prod_decimal FROM @data 
UNION
SELECT Line, STR_ORDER_ID, 3 , 'GAP' , @Gap FROM @data )  u -- this adds dummy data that will act as gaps in hte timeline. Change 5 to whatever value suits you best
    ORDER BY Line, STR_ORDER_ID, OperationOrder

-- find the largest line running total duration per line and scale it to fit to 240 (so we dont go over 256 column limit in SSRS)
DECLARE @MaxDur INT = (SELECT MAX(rt) FROM (
                        select  *
                            , SUM(Duration) OVER(PARTITION BY Line ORDER BY Line, STR_ORDER_ID, OperationOrder) AS Rt
                         from @normData) mRt)


-- Now scale the values back so they fit but don't let any value become less than 1
IF @MaxDur > 240
    BEGIN
        UPDATE nd 
            SET Duration = CASE WHEN nd.Duration / (@MaxDur/240) <1 THEN 1 ELSE nd.Duration / (@MaxDur/240) END
            FROM @normData nd
    END

/* check what we have so far by uncommenting this bit
select  *
    , SUM(Duration) OVER(PARTITION BY Line ORDER BY Line, STR_ORDER_ID, OperationOrder) AS Rt
 from @normData
--*/    

-- ================================================================ --
-- At this point you 'may' have enough data to plot a bar chart. == --
-- ================================================================ --

-- CREATE A SIMPLE NUMBERS TABLE, we'll need this to act as our time series
DECLARE @n TABLE(n int)
DECLARE @i int  = 0
DECLARE @t int  = @MaxDur --(SELECT max(Duration) +5 FROM @normData) -- simple loop counter target set to slightly bigger than our highest duration
WHILE @i<@t
    BEGIN
        INSERT INTO @n SELECT @i
        SET @i = @i +1
    END

-- Join our numbers table to our real data
-- This will give us at least 1 row per time slot and associated activity during that time slot.
-- We can plot this driectly as a matrix.
SELECT * 
    FROM @n n
        LEFT JOIN ( 
                -- Sub queries below give use a runnintg total, we then join this back to itself to get the previous 
                -- running total and this will give us the 'time range' for each operation.
                SELECT 
                    a.*
                    , ISNULL(b.Rt,0)+1 AS TimeStart
                    , a.RT AS TimeEnd
                    FROM
                    (SELECT *
                            , SUM(Duration) OVER(PARTITION BY Line ORDER BY Line, STR_ORDER_ID, OperationOrder) AS Rt
                         from @normData
                    ) a
                LEFT JOIN 
                    (SELECT *
                            , SUM(Duration) OVER(PARTITION BY Line ORDER BY Line, STR_ORDER_ID, OperationOrder) AS Rt
                         from @normData
                    ) b
                    ON a.RowId = b.RowId + 1 and a.Line = b.Line 
                ) d
            ON n.n between d.TimeStart and d.TimeEnd
    ORDER BY Line, STR_ORDER_ID, OperationOrder, n, TimeStart, TimeEnd

您可以在数据集中使用上面的代码。

报告设计: 报告非常简单。这是一个基于Line 的单行组和基于n 的单列组的矩阵,n 是我们的时隙号。

我添加了一个空白行作为“条”之间的间隔。

单元格背景的表达式为

=SWITCH(
Fields!OperationOrder.Value = 1, "Yellow",
Fields!OperationOrder.Value = 2, "Green",
Fields!OperationOrder.Value = 3, Nothing,
True, Nothing
)

还有一个工具提示,显示 STR_ORDER_ID 和操作名称。

你会得到以下输出。

【讨论】:

  • 感谢您的帮助艾伦! :) 但我仍然无法报告。我不明白如何创建矩阵报告?
  • 只需右键单击设计图面,插入/矩阵。将 LINE 拖到左列,将 N 拖到右列 header 并可选择将“操作”拖到数据单元格中(右下角标记为空白时的数据)。那应该创建行和列组。您可以在设计区域的底部看到组。完成后,对其进行测试,您将在每个单元格中看到操作名称。然后删除不需要的数据单元格,将数据列宽度设置为0.3cm之类的小值,并将背景颜色表达式设置为示例中的SWITCH语句。
  • 你好艾伦,我无法在下面回答。这就是为什么我在上面编辑我的问题。你对我的问题有什么建议吗_
  • 原代码有个bug,我已经更正了,其他部分我也改了,因为数据的格式和以前不一样了。
  • 非常感谢您的帮助 :) 我确实喜欢这个,但在 productıon 环境中我的程序运行非常缓慢,这就是为什么我想也许我可以使用范围(甘特)图,但如果我使用甘特图,我将面临对于这个问题link你有什么关于这个问题的建议吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-31
  • 1970-01-01
相关资源
最近更新 更多