如何在SSRS中显示包含按组列出的名称列表的宽表?

huangapple go评论60阅读模式
英文:

How do I display a wide table in SSRS containing lists of names by group?

问题

我理解你的需求。以下是你提供的内容的翻译:

我有一份分配给不同班级的学生名单。每个学生只属于一个班级。每个班级中的学生人数并不总是相同。

我希望在SSRS中显示它们,其中每个班级都是一列,学生的姓名显示在班级标题下,就像这样:

  Class1  |  Class2  |  Class3  | ...
-------------------------------------------
Student1  | Student4 | Student6 | ...
Student2  | Student5 | Student7 |
Student3  |          | Student8 |

我尝试在SSRS中使用矩阵,但一直遇到问题,因为我得到的矩阵看起来像这样:

  Class1  |  Class2  |  Class3  | ...
-------------------------------------------
Student1  |          |          |
          |Student4  |          |
          |          | Student6 | 
Student2  |          |          |

我考虑过使用SQL的PIVOT函数,但必须指定要进行枢轴操作的值,而我希望表格根据数据中的内容动态生成。

有没有实现这个目标的方法?

感谢大家的时间。

编辑:我还应该指出,即使我在不使用动态SQL的情况下进行测试,也无法使PIVOT正常工作。例如:

select * 
from (
    select Name, Class
    from (values 
        ('Student1', 'Class1'),
        ('Student2', 'Class1'),
        ('Student3', 'Class1'),
        ('Student4', 'Class2'),
        ('Student5', 'Class2'),
        ('Student6', 'Class3'),
        ('Student7', 'Class3'),
        ('Student8', 'Class3'),
        ('Student9', 'Class3')
        ) as T(Name, Class)
    ) as T
    PIVOT (
        max(Name)
        for Class in ([Class1],[Class2],[Class3])
    ) as P

输出:

Class1      Class2      Class3
Student3	Student5	Student9

PIVOT的另一个问题是,我理想情况下希望使用其他数据元素来格式化SSRS报表中的单元格(例如,学生的性别来设置单元格的填充颜色等)。如果数据进行了枢轴操作,它可能会提供所需的列表,但将其他数据元素整合到报表中将会很困难,除了学生姓名等数据元素之外。

英文:

I have a list of students assigned to classes. Each student is in one class only. The numbers of students in each class is not always the same.

Student1,Class1
Student2,Class1
Student3,Class1
Student4,Class2
Student5,Class2
Student6,Class3
...

I want to display them in SSRS where each class is a column, and the names of students appear under the class heading, like this:

  Class1  |  Class2  |  Class3  | ...
-------------------------------------------
Student1  | Student4 | Student6 | ...
Student2  | Student5 | Student7 |
Student3  |          | Student8 |

I tried using a matrix in SSRS, but have struggled because I keep getting a matrix like this:

  Class1  |  Class2  |  Class3  | ...
-------------------------------------------
Student1  |          |          |
          |Student4  |          |
          |          | Student6 | 
Student2  |          |          |

I thought about using a SQL PIVOT function but you have to specify the pivoting values, and I would like the table to generate dynamically based on what is found in the data.

Is there any way of achieving this?

Thank you all for your time.

Edit: I also should point out that I can't get a PIVOT to work correctly either, even if I test it without using Dynamic SQL. For example:

select * 
from (
    select Name, Class
    from (values 
        ('Student1', 'Class1'),
        ('Student2', 'Class1'),
        ('Student3', 'Class1'),
        ('Student4', 'Class2'),
        ('Student5', 'Class2'),
        ('Student6', 'Class3'),
        ('Student7', 'Class3'),
        ('Student8', 'Class3'),
        ('Student9', 'Class3')
        ) as T(Name, Class)
    ) as T
    PIVOT (
        max(Name)
        for Class in ([Class1],[Class2],[Class3])
    ) as P

Output:

Class1      Class2      Class3
Student3	Student5	Student9

A further problem with PIVOT is that I would ideally like to use other data elements to format cells in the SSRS report (e.g. student gender to set fill colour of cell and so forth). If the data is pivoted it may provide lists as required, but it will be difficult to incorporate other data elements aside from Student Name etc.

答案1

得分: 2

以下是翻译好的内容:

你可以轻松地完成这个任务。

这是你的示例数据,以及一个计算列,该列为每个学生提供了一个行号。

DECLARE @t TABLE (StudentName varchar(20), ClassName varchar(20))
INSERT INTO @t values 
        ('Student1', 'Class1'),
        ('Student2', 'Class1'),
        ('Student3', 'Class1'),
        ('Student4', 'Class2'),
        ('Student5', 'Class2'),
        ('Student6', 'Class3'),
        ('Student7', 'Class3'),
        ('Student8', 'Class3'),
        ('Student9', 'Class3')

SELECT 
    StudentName, ClassName
    , RowN = ROW_NUMBER() OVER(PARTITION BY ClassName ORDER BY StudentName)
    FROM @t

现在,你只需要创建一个矩阵,将Class拖动到列组中,将RowN拖动到行组中,最后将学生的姓名拖动到数据单元格中,基本上就是你需要做的全部。

这里有一个40秒的gif图,首先显示了上面查询的输出,然后切换到报告设计器,在那里我已经添加了包含相同查询的数据集。

如果你想要放大并更容易观看,请右键单击并选择“在新标签页/窗口中打开链接”。

如何在SSRS中显示包含按组列出的名称列表的宽表?

英文:

You can easily do this.

Here's your sample data, plus a calulated column that gives you a row number per student

DECLARE @t TABLE (StudentName varchar(20), ClassName varchar(20))
INSERT INTO @t values 
        ('Student1', 'Class1'),
        ('Student2', 'Class1'),
        ('Student3', 'Class1'),
        ('Student4', 'Class2'),
        ('Student5', 'Class2'),
        ('Student6', 'Class3'),
        ('Student7', 'Class3'),
        ('Student8', 'Class3'),
        ('Student9', 'Class3')
        
SELECT 
    StudentName, ClassName
    , RowN = ROW_NUMBER() OVER(PARTITION BY ClassName ORDER BY StudentName)
    FROM @t         

Now all you need to do is create a matrix, drag the Class as the column group and RowN as the row group and finally drag the student name to the data 'cell' and that's pretty much all you have to do.

Here's a 40 seconds gif that first shows the output from the query above, it then switches to the the report designer where I have already added a dataset containing the same query.

Right-click and "Open Link In New Tab/Window" if you want to make it bigger and easier to watch.

如何在SSRS中显示包含按组列出的名称列表的宽表?

答案2

得分: 1

使用“动态SQL”根据表中的数据生成透视值,然后执行生成的透视查询,例如:

DECLARE @cols AS NVARCHAR(MAX),
        @query AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Class)
                      FROM students
                      FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');

SET @query = N'WITH CTE AS (
    SELECT Name, Class, ROW_NUMBER() OVER (PARTITION BY Class ORDER BY Name) AS RowNum
    FROM students
)
SELECT ' + @cols + '
FROM CTE
PIVOT (
    MAX(Name)
    FOR Class IN (' + @cols + ')
) AS pvt
ORDER BY RowNum;';

EXECUTE sp_executesql @query;

对于SSRS,将动态SQL放在存储过程中,然后将该存储过程用作SSRS报表的数据源。即在数据库中创建一个新的存储过程,将动态SQL代码粘贴到其中。确保将[YourTable]替换为实际表名。

CREATE PROCEDURE [dbo].[usp_YourProcedureName]
AS
BEGIN
    DECLARE @cols AS NVARCHAR(MAX),
            @query AS NVARCHAR(MAX);

    SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Class)
                          FROM students
                          FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');

    SET @query = N'WITH CTE AS (
        SELECT Name, Class, ROW_NUMBER() OVER (PARTITION BY Class ORDER BY Name) AS RowNum
        FROM students
    )
    SELECT ' + @cols + '
    FROM CTE
    PIVOT (
        MAX(Name)
        FOR Class IN (' + @cols + ')
    ) AS pvt
    ORDER BY RowNum;';

    EXECUTE sp_executesql @query;
END

在SSRS报表中,创建一个新的数据集,并将其数据源设置为刚刚创建的存储过程。使用此数据集填充报表中的矩阵。将学生列设置为行组,将班级列设置为列组。

注意

如果动态生成了大量列,可能会导致SSRS报表的宽度问题。处理此问题的一种方法是将列的CanGrow属性设置为True,将CanShrink属性设置为False。这将允许列在宽度上增长以适应数据。

另一种处理方法是将矩阵的LayoutDirection属性设置为Vertical。这将导致矩阵垂直增长而不是水平增长,有助于解决宽度问题。

也可以尝试调整字体大小和列宽度的大小,以便在页面上容纳更多列。

英文:

Use "dynamic SQL" to generate the pivot values based on the data in your table, then excute that generated pivot query e.g:

DECLARE @cols AS NVARCHAR(MAX),
        @query AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Class)
                      FROM students
                      FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');

SET @query = N'WITH CTE AS (
    SELECT Name, Class, ROW_NUMBER() OVER (PARTITION BY Class ORDER BY Name) AS RowNum
    FROM students
)
SELECT ' + @cols + '
FROM CTE
PIVOT (
    MAX(Name)
    FOR Class IN (' + @cols + ')
) AS pvt
ORDER BY RowNum;';

EXECUTE sp_executesql @query;

For SSRS, use the dynamic SQL inside in a stored procedure and then use that stored procedure as the data source for your SSRS report. i.e. Create a new stored procedure in your database and paste the dynamic SQL code into it. Make sure to replace [YourTable] with the real name.

CREATE PROCEDURE [dbo].[usp_YourProcedureName]
AS
BEGIN
    DECLARE @cols AS NVARCHAR(MAX),
            @query AS NVARCHAR(MAX);

    SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Class)
                          FROM students
                          FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');

    SET @query = N'WITH CTE AS (
        SELECT Name, Class, ROW_NUMBER() OVER (PARTITION BY Class ORDER BY Name) AS RowNum
        FROM students
    )
    SELECT ' + @cols + '
    FROM CTE
    PIVOT (
        MAX(Name)
        FOR Class IN (' + @cols + ')
    ) AS pvt
    ORDER BY RowNum;';

    EXECUTE sp_executesql @query;
END
  • In your SSRS report, create a new dataset and set its data source to the stored procedure you just created.
  • Use this dataset to populate a matrix in your report. Set the Student column as the row group and the Class columns as the column group.

NOTE

If you have a large number of columns generated dynamically, it can cause width issues in your SSRS report. One way to handle this is to set the CanGrow property of the column to True and the CanShrink property to False. This will allow the column to grow in width to accommodate the data.

Another way to handle this is to set the LayoutDirection property of the matrix to Vertical. This will cause the matrix to grow vertically instead of horizontally, which can help with width issues.

Perhaps also try adjusting the size of the font and the column width to fit more columns on the page.

fiddle

huangapple
  • 本文由 发表于 2023年5月18日 10:11:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76277301.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定