如何在SSRS上设计条形图

How to design bar chart on SSRS

我想在 SSRS 上创建如下图所示的报告。

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

我的查询结果是这样的:

我想按行显示所有订单,我想按订单显示,设置和生产取决于持续时间。

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"这个订单通常有设置阶段,但在报告上我没有黄色字段。

你对我有什么建议吗?

好吧,这是给你想要的东西的尝试,但有一些注意事项:

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

首先是代码...我已经添加了很多评论,希望您能理解它,它基于您的样本数据。

注意:我已经更新了 table,因为现在您似乎使用的是整数持续时间,而不是第一个示例中的 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 的单列组,这是我们的时隙编号。

我添加了一个空白行作为 'bars' 之间的分隔符。

单元格背景的表达式为

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

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

你得到以下输出。