SSRS 报表多值报表过滤和分组
SSRS report multivalue report filtering and grouping
让我们从基础开始。以下是报告中数据的简化结构:
ID | Tags
1 |A|
2 |A|B|
3 |B|
4 |A|C|D|
5 |B|D|
6 |D|A|C| --I added this row to show that tags could be in any order
我在报表上有一个参数,用户可以在其中从列表 (A,B,C,D) 中选择一个或多个标签
这是我希望在报告中看到的输出。它将导出到 Excel,因此我将使用它来描述所需的输出。
示例报告输出:(标记参数选择:A 和 D)
工作表 1 = 显示所有记录 => [1,2,3,4,5,6]
工作表 2 = 显示匹配所有选定标签的记录(A AND D 必须有标签!)=> [4 ,6]
工作表 3 = 显示具有标记 A => [1,2,4,6]
的记录
工作表 4 = 显示具有标记 D => [4,5,6]
的记录
**注意:工作表 3 及以上将显示在单独工作表中选择的每个标签,可能有 1 到 N 个工作表。
目前在报告中我准备好了 3 个表:
Table 1:只显示完整的查询(非常简单!)并且有一个 PageName="All records"
Table 2:需要过滤完整查询以匹配上面的工作表 2,并且将有一个 PageName="Filtered records" 这是问题 #1!寻找有关过滤器查询的想法!
Table 3:需要将完整查询按标签分组,但也只显示标签在参数中选择的标签列表中的分组。 这是问题 #2!不能只从 Table 2 中获取过滤器然后分组,因为记录会丢失(例如标记 D 的数字 5)
任何帮助将不胜感激!!
补充说明:
- 可以更改标记分隔符(我选择 | 因为数据有逗号)
- 无论分隔符如何,由于在其他列中聚合,标签只能在一列(分隔列表)中返回
这里有几个问题要问。我先处理能让您查询更简单的问题。
我不确定我是否符合您的标准,因为我不理解您所说的某些内容,但无论如何,它可能会为您指明正确的方向。
如果您还没有拆分函数,请在您的数据库中创建一个拆分函数
如果你没有,你可以使用我几年前创建的这个。它并不完美,但适合我。
CREATE FUNCTION [fnSplit](@sText varchar(8000), @sDelim varchar(20) = ' ')
RETURNS @retArray TABLE (idx smallint Primary Key, value varchar(8000))
AS
BEGIN
DECLARE @idx smallint,
@value varchar(8000),
@bcontinue bit,
@iStrike smallint,
@iDelimlength tinyint
IF @sDelim = 'Space'
BEGIN
SET @sDelim = ' '
END
SET @idx = 0
SET @sText = LTrim(RTrim(@sText))
SET @iDelimlength = DATALENGTH(@sDelim)
SET @bcontinue = 1
IF NOT ((@iDelimlength = 0) or (@sDelim = 'Empty'))
BEGIN
WHILE @bcontinue = 1
BEGIN
--If you can find the delimiter in the text, retrieve the first element and
--insert it with its index into the return table.
IF CHARINDEX(@sDelim, @sText)>0
BEGIN
SET @value = SUBSTRING(@sText,1, CHARINDEX(@sDelim,@sText)-1)
BEGIN
INSERT @retArray (idx, value)
VALUES (@idx, @value)
END
--Trim the element and its delimiter from the front of the string.
--Increment the index and loop.
SET @iStrike = DATALENGTH(@value) + @iDelimlength
SET @idx = @idx + 1
SET @sText = LTrim(Right(@sText,DATALENGTH(@sText) - @iStrike))
END
ELSE
BEGIN
--If you can't find the delimiter in the text, @sText is the last value in
--@retArray.
SET @value = @sText
BEGIN
INSERT @retArray (idx, value)
VALUES (@idx, @value)
END
--Exit the WHILE loop.
SET @bcontinue = 0
END
END
END
ELSE
BEGIN
WHILE @bcontinue=1
BEGIN
--If the delimiter is an empty string, check for remaining text
--instead of a delimiter. Insert the first character into the
--retArray table. Trim the character from the front of the string.
--Increment the index and loop.
IF DATALENGTH(@sText)>1
BEGIN
SET @value = SUBSTRING(@sText,1,1)
BEGIN
INSERT @retArray (idx, value)
VALUES (@idx, @value)
END
SET @idx = @idx+1
SET @sText = SUBSTRING(@sText,2,DATALENGTH(@sText)-1)
END
ELSE
BEGIN
--One character remains.
--Insert the character, and exit the WHILE loop.
INSERT @retArray (idx, value)
VALUES (@idx, @sText)
SET @bcontinue = 0
END
END
END
RETURN
END
此函数只是将分隔的字符串拆分为 table 的组件。
然后我们可以使用 CROSS APPLY
为我们提供一个应该更易于使用的结果集。例如,我重新创建了您的示例数据,然后像这样使用 CROSS APPLY
...
DECLARE @t table(ID int, Tags varchar(100))
INSERT INTO @t VALUES
(1,'|A|'),
(2,'|A|B|'),
(3,'|B|'),
(4,'|A|C|D|'),
(5,'|B|D|'),
(6,'|D|A|C|')
SELECT * FROM @t t
CROSS APPLY fnSplit(Tags,'|') f
WHERE f.Value != ''
这给了我们这个输出
ID Tags idx value
1 |A| 1 A
2 |A|B| 1 A
2 |A|B| 2 B
3 |B| 1 B
4 |A|C|D| 1 A
4 |A|C|D| 2 C
4 |A|C|D| 3 D
5 |B|D| 1 B
5 |B|D| 2 D
6 |D|A|C| 1 D
6 |D|A|C| 2 A
6 |D|A|C| 3 C
要获取所有记录只需执行
SELECT DISTINCT t.* FROM @t t
CROSS APPLY fnSplit(Tags,'|') f
WHERE f.Value != ''
要获取过滤后的记录,假设您有一个名为 @pTags
的参数,然后将数据集语句更改为
SELECT DISTINCT t.ID, f.Value FROM @t t
CROSS APPLY fnSplit(Tags,'|') f
WHERE f.Value != ''
and f.Value IN (@pTags)
只要这直接在您的数据集查询中并且参数是多值,那么这应该正确过滤,如果需要请使用 DISTINCT。
让我们从基础开始。以下是报告中数据的简化结构:
ID | Tags
1 |A|
2 |A|B|
3 |B|
4 |A|C|D|
5 |B|D|
6 |D|A|C| --I added this row to show that tags could be in any order
我在报表上有一个参数,用户可以在其中从列表 (A,B,C,D) 中选择一个或多个标签
这是我希望在报告中看到的输出。它将导出到 Excel,因此我将使用它来描述所需的输出。
示例报告输出:(标记参数选择:A 和 D)
工作表 1 = 显示所有记录 => [1,2,3,4,5,6]
工作表 2 = 显示匹配所有选定标签的记录(A AND D 必须有标签!)=> [4 ,6]
工作表 3 = 显示具有标记 A => [1,2,4,6]
的记录工作表 4 = 显示具有标记 D => [4,5,6]
的记录**注意:工作表 3 及以上将显示在单独工作表中选择的每个标签,可能有 1 到 N 个工作表。
目前在报告中我准备好了 3 个表:
Table 1:只显示完整的查询(非常简单!)并且有一个 PageName="All records"
Table 2:需要过滤完整查询以匹配上面的工作表 2,并且将有一个 PageName="Filtered records" 这是问题 #1!寻找有关过滤器查询的想法!
Table 3:需要将完整查询按标签分组,但也只显示标签在参数中选择的标签列表中的分组。 这是问题 #2!不能只从 Table 2 中获取过滤器然后分组,因为记录会丢失(例如标记 D 的数字 5)
任何帮助将不胜感激!!
补充说明:
- 可以更改标记分隔符(我选择 | 因为数据有逗号)
- 无论分隔符如何,由于在其他列中聚合,标签只能在一列(分隔列表)中返回
这里有几个问题要问。我先处理能让您查询更简单的问题。
我不确定我是否符合您的标准,因为我不理解您所说的某些内容,但无论如何,它可能会为您指明正确的方向。
如果您还没有拆分函数,请在您的数据库中创建一个拆分函数 如果你没有,你可以使用我几年前创建的这个。它并不完美,但适合我。
CREATE FUNCTION [fnSplit](@sText varchar(8000), @sDelim varchar(20) = ' ')
RETURNS @retArray TABLE (idx smallint Primary Key, value varchar(8000))
AS
BEGIN
DECLARE @idx smallint,
@value varchar(8000),
@bcontinue bit,
@iStrike smallint,
@iDelimlength tinyint
IF @sDelim = 'Space'
BEGIN
SET @sDelim = ' '
END
SET @idx = 0
SET @sText = LTrim(RTrim(@sText))
SET @iDelimlength = DATALENGTH(@sDelim)
SET @bcontinue = 1
IF NOT ((@iDelimlength = 0) or (@sDelim = 'Empty'))
BEGIN
WHILE @bcontinue = 1
BEGIN
--If you can find the delimiter in the text, retrieve the first element and
--insert it with its index into the return table.
IF CHARINDEX(@sDelim, @sText)>0
BEGIN
SET @value = SUBSTRING(@sText,1, CHARINDEX(@sDelim,@sText)-1)
BEGIN
INSERT @retArray (idx, value)
VALUES (@idx, @value)
END
--Trim the element and its delimiter from the front of the string.
--Increment the index and loop.
SET @iStrike = DATALENGTH(@value) + @iDelimlength
SET @idx = @idx + 1
SET @sText = LTrim(Right(@sText,DATALENGTH(@sText) - @iStrike))
END
ELSE
BEGIN
--If you can't find the delimiter in the text, @sText is the last value in
--@retArray.
SET @value = @sText
BEGIN
INSERT @retArray (idx, value)
VALUES (@idx, @value)
END
--Exit the WHILE loop.
SET @bcontinue = 0
END
END
END
ELSE
BEGIN
WHILE @bcontinue=1
BEGIN
--If the delimiter is an empty string, check for remaining text
--instead of a delimiter. Insert the first character into the
--retArray table. Trim the character from the front of the string.
--Increment the index and loop.
IF DATALENGTH(@sText)>1
BEGIN
SET @value = SUBSTRING(@sText,1,1)
BEGIN
INSERT @retArray (idx, value)
VALUES (@idx, @value)
END
SET @idx = @idx+1
SET @sText = SUBSTRING(@sText,2,DATALENGTH(@sText)-1)
END
ELSE
BEGIN
--One character remains.
--Insert the character, and exit the WHILE loop.
INSERT @retArray (idx, value)
VALUES (@idx, @sText)
SET @bcontinue = 0
END
END
END
RETURN
END
此函数只是将分隔的字符串拆分为 table 的组件。
然后我们可以使用 CROSS APPLY
为我们提供一个应该更易于使用的结果集。例如,我重新创建了您的示例数据,然后像这样使用 CROSS APPLY
...
DECLARE @t table(ID int, Tags varchar(100))
INSERT INTO @t VALUES
(1,'|A|'),
(2,'|A|B|'),
(3,'|B|'),
(4,'|A|C|D|'),
(5,'|B|D|'),
(6,'|D|A|C|')
SELECT * FROM @t t
CROSS APPLY fnSplit(Tags,'|') f
WHERE f.Value != ''
这给了我们这个输出
ID Tags idx value
1 |A| 1 A
2 |A|B| 1 A
2 |A|B| 2 B
3 |B| 1 B
4 |A|C|D| 1 A
4 |A|C|D| 2 C
4 |A|C|D| 3 D
5 |B|D| 1 B
5 |B|D| 2 D
6 |D|A|C| 1 D
6 |D|A|C| 2 A
6 |D|A|C| 3 C
要获取所有记录只需执行
SELECT DISTINCT t.* FROM @t t
CROSS APPLY fnSplit(Tags,'|') f
WHERE f.Value != ''
要获取过滤后的记录,假设您有一个名为 @pTags
的参数,然后将数据集语句更改为
SELECT DISTINCT t.ID, f.Value FROM @t t
CROSS APPLY fnSplit(Tags,'|') f
WHERE f.Value != ''
and f.Value IN (@pTags)
只要这直接在您的数据集查询中并且参数是多值,那么这应该正确过滤,如果需要请使用 DISTINCT。