好久没有写博客了,最近更新完善修复了SSRS报表的一些问题,和大家分享。
问题描述:
报表中,区域->专区->省份->地级市 此四个筛选参数是联动的,在DataSet中前一父级参数作为where条件带入。
现在发现问题是:开始打开报表时,所有都是全选,OK!然后都选一个区域,比如华南,专区也自动筛选啊全选,OK!但是再次重新勾选两个区域,如'华南,京津冀蒙',专区虽然下拉选框中正确显示了所属级联的专区字段,但是却没有全部勾选上!
Step1:如图1中父级参数:区域。在第一次打开报表后默认全选,子节点专区全部正常,且全部默认全选。
Step2: 区域中选择,华南后,子级节点默认全选华南所属专区,正常。
Step3: 当再次复选或者重新全选父节点只有,子节点数据也全部刷新,但是并没有默认全选如图2,导致用户查询数据结果仍是上一次查询结果。
如下图:
网上看了很多,google也找了很多,大家都一认为这是微软产品的一个BUG,,我也确实这么认为。
解决方案:
之前有网友提供了两种解决方案:
1.返回的数据集添加了一个all选项,排在第一行,然后存储过程中去判断传入的是否含有all,有的话就不加筛选条件,否则就用in来处理。
<这个我最开始也是这样做的,但是后来我们添加了对于参数的权限管理,根据每个人的AD账号给予对应区域权限显示,所以添加ALL字段反而对于procedure里的参数分支判断更为复杂,所以摒弃!>
2.开发是通过reportview控件的话直接用C#开发的网页,当父项参数选定后,C#会获取其所对应的所有子项参数,然后刷新报表,把子项参数传过去。
<因为我是用VS中直接新建的'报表服务器项目'解决方案,然后直接部署到sharepoint上,所以不好集成,此方案摒弃!>
3.重点:
参考了一篇twitter上某大神分享的文章,是一种workaround的方案,可以说是迂回方案吧,完美解决!所以接下来我讲一下重点步骤。
注:英文原版,请直接移步文章:http://www.bp-msbi.com/2011/04/ssrs-cascading-parameters-refresh-solved/
原理也没看很明白,大致是说,微软认为应该保留上一次未更改的筛选数据,所以我们的解决思路就是:
STEP1:让每一次DataSet集合返回的key值字段都是不同的(label字段不变),所以用newid()函数拼接一个新字段,作为参数取用的时候在截取所需字段即可。
STEP2:改设原参数为internal(内部参数),增加一个新参数获取原参数的值<value>和标签<label>,并修改对于获取事实表即显示在table中的dataset的存储过程中,参数传值改为新的参数。
STEP3:设置完后正常应该已经OK了,但是如果你在级联参数之前还有其他的,则需要设置默认值,这样才会自动加载,否则必须前面所有参数值选定之后,才会显现效果!
以下是修改后存储过程:
区域字段:REGIONLIST_procedure
1 USE [DM_ACCN_T1] 2 GO 3 4 /****** Object: StoredProcedure [dbo].[SSRS_PARAM_CONREGION_LIST] Script Date: 2016/8/5 11:38:39 ******/ 5 SET ANSI_NULLS ON 6 GO 7 8 SET QUOTED_IDENTIFIER ON 9 GO 10 11 12 13 -- ============================================= 14 -- Author: Ammy Guo 15 -- Create date: 2016/06/24 16 -- Description: SSRS_RAW_DISTBO 17 -- ============================================= 18 CREATE PROCEDURE [dbo].[SSRS_PARAM_CONREGION_LIST] 19 20 @UserName VARCHAR(20) 21 AS 22 BEGIN 23 -- SET NOCOUNT ON added to prevent extra result sets from 24 -- interfering with SELECT statements. 25 SET NOCOUNT ON; 26 DECLARE @ConRegion_Code NVARCHAR(500) 27 DECLARE @Aera_Code NVARCHAR(10) 28 29 SELECT DISTINCT @ConRegion_Code=REGION_EN, @Aera_Code=AREA_CODE FROM [DM_ACCN_T1].[dbo].[CB_UI_MS_DIMENSION_SECURITY] 30 WHERE USERID=@UserName AND [SOURCE]='ACCN_T1 Raw Data' 31 32 IF(charindex('*',@ConRegion_Code)>0) 33 BEGIN 34 IF @Aera_Code='CHINA' 35 BEGIN 36 --SELECT 'ALL'AS CON_REGION_CODE,'ALL'AS CON_REGION_EN,'ALL'AS CON_REGION_CN 37 --UNION ALL 38 SELECT DISTINCT CON_REGION_CODE, CON_REGION_EN, CON_REGION_CN 39 FROM CB_GEOGRAPHY WHERE AREA_CODE='CHINA' 40 END 41 ELSE IF @Aera_Code='HONGKONG' 42 BEGIN 43 --SELECT 'ALL'AS CON_REGION_CODE,'ALL'AS CON_REGION_EN,'ALL'AS CON_REGION_CN 44 --UNION ALL 45 SELECT DISTINCT CON_REGION_CODE, CON_REGION_EN, CON_REGION_CN 46 FROM CB_GEOGRAPHY WHERE AREA_CODE='HONGKONG' 47 END 48 ELSE 49 BEGIN 50 SELECT DISTINCT CON_REGION_CODE, CON_REGION_EN, CON_REGION_CN FROM CB_GEOGRAPHY 51 END 52 END 53 ELSE 54 BEGIN 55 --SELECT 'ALL'AS CON_REGION_CODE,'ALL'AS CON_REGION_EN,'ALL'AS CON_REGION_CN 56 --UNION ALL 57 SELECT DISTINCT B.CON_REGION_CODE as CON_REGION_CODE,REGION_EN as CON_REGION_EN,B.CON_REGION_CN as CON_REGION_CN FROM [DM_ACCN_T1].[dbo].[CB_UI_MS_DIMENSION_SECURITY] A 58 LEFT OUTER JOIN CB_GEOGRAPHY B ON A.REGION_EN=B.CON_REGION_EN 59 WHERE USERID=@UserName AND [SOURCE]='ACCN_T1 Raw Data' 60 END 61 62 63 END 64 65 66 67 68 GO
专区字段:SUBREGION_procedure
CREATE PROCEDURE [dbo].[SSRS_PARAM_CONSUBREGION_LIST] @UserName VARCHAR(20), @CON_REGION VARCHAR(MAX) AS BEGIN SET NOCOUNT ON; DECLARE @GID VARCHAR(36)=CONVERT(varchar(36),NEWID()); SELECT DISTINCT CONVERT(VARCHAR(10),CON_SUBREIGON_CODE)+@GID AS CON_SUBREIGON_CODE, CON_SUBREGION_EN, CON_SUBREION_CN FROM CB_GEOGRAPHY WHERE (CON_REGION_EN IN (SELECT value from [dbo].[fnSplitStr](@CON_REGION,','))) END
省份字段:PROVINCE_procedure
CREATE PROCEDURE [dbo].[SSRS_PARAM_PROVINCE_LIST] @UserName VARCHAR(20), @CON_REGION VARCHAR(MAX), @CON_SUBREGION VARCHAR(MAX) AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; DECLARE @GID VARCHAR(36)=CONVERT(varchar(36),NEWID()); SELECT DISTINCT CONVERT(VARCHAR(10),PROVINCE_CODE) + @GID AS PROVINCE_CODE, PROVINCE_CN FROM CB_GEOGRAPHY WHERE CON_REGION_EN IN (SELECT value from [dbo].[fnSplitStr](@CON_REGION,',')) AND CON_SUBREIGON_CODE IN (SELECT REPLACE(value,RIGHT(value,36),'') from [dbo].[fnSplitStr](@CON_SUBREGION,',')) ORDER BY PROVINCE_CN ASC END
地级市字段:DIJISHI_procedure
CREATE PROCEDURE [dbo].[SSRS_PARAM_DIJICITY_LIST] @UserName VARCHAR(20), @CON_REGION VARCHAR(MAX), @CON_SUBREGION VARCHAR(MAX), @PROVINCE VARCHAR(MAX) AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; DECLARE @GID VARCHAR(36)=CONVERT(varchar(36),NEWID()); SELECT DISTINCT CONVERT(VARCHAR(10),DIJI_CITY_CODE) + @GID AS DIJI_CITY_CODE, DIJI_CITY_NAME_CN FROM CB_GEOGRAPHY WHERE CON_REGION_EN IN (SELECT value from [dbo].[fnSplitStr](@CON_REGION,',')) AND CON_SUBREIGON_CODE IN (SELECT REPLACE(value,RIGHT(value,36),'') from [dbo].[fnSplitStr](@CON_SUBREGION,',')) AND PROVINCE_CODE IN (SELECT REPLACE(value,RIGHT(value,36),'') from [dbo].[fnSplitStr](@PROVINCE,',')) order by DIJI_CITY_CODE desc END
接下来是报表DEALERSTOCK.rdl的改动(如DealerStock):
接下来给开始日期和结束日期增加了一个默认值,做法是:添加了一个共用数据集,已文本形式编写的一句简单sql获取当天时间为开始时间和结束时间作为默认值,注意是:date类型。
获取时间:sql juery text
SELECT CAST(CONVERT(VARCHAR(10),GETDATE(),111)AS DATE) AS STARTDATE,CAST(CONVERT(VARCHAR(10),GETDATE(),111)AS DATE) AS ENDDATE
最后注意别忘了,事实集dataset的procedure要修改传入的参数,并且注意where条件中参数的截取:
完成效果(这个workaround方案会导致第一次打开报表时,就会加载报表数据-因为所有参数已经默认完成。):