我可以提出以下解决方案(请不要太严格地判断,这只是一个想法):与其在第一行中使用虚拟的“用户名”作为列名,为什么不放真实的用户名并同意/每个用户/项目的行/列交叉处没有标记。见下图。这是各种成员表或玩家评分表中的常见视图类型(但它们在垂直和水平方向上具有相同的名称)。
我已插入测试成员记录,因此您可以看到 Mark 是所有项目中的成员,而 Bryan 仅是 SQL 中的成员。
此动态 SQL 产生上述输出:
DECLARE @dynPivotSQL AS NVARCHAR(MAX)
DECLARE @pivotColNames AS NVARCHAR(MAX)
DECLARE @pivotColNamesMin AS NVARCHAR(MAX)
-- get distinct username for column headers
SELECT @pivotColNames= ISNULL(@pivotColNames + ',','')
+ QUOTENAME(UserName),
@pivotColNamesMin= ISNULL(@pivotColNamesMin + ',','')
+ 'min(' + QUOTENAME(UserName) +') as ' + QUOTENAME(UserName)
FROM (SELECT DISTINCT UserName, UserID FROM Users) AS U
SET @dynPivotSQL = N'
with cte as (
select p.ProjectName,u.UserName,IsMember=1 from ProjectsUsers pu
join Projects p on p.ProjectID = pu.FK_ProjectID
join Users u on u.UserID = pu.FK_UserID
) select ProjectName, ' + @pivotColNamesMin + ' from cte
pivot (
min(IsMember) for UserName in (' + @pivotColNames + ')
) pvt
group by ProjectName '
EXEC sp_executesql @dynPivotSQL
注意,由于您的要求是拥有项目/用户的动态列表,因此我必须使用动态 sql 为 T-SQL PIVOT 创建动态列列表,该列表通常与硬编码/静态值/列名一起使用。
请注意,在使用的数据透视块中还有一个 min(IsMember) 技巧,因为数据透视需要包含一些聚合函数,但我们不能执行 min(UserName),因为它实际上会返回特定项目成员集中的最小名称名字。
@pivotColNamesMin 是另一个技巧,现在用于 GROUP BY,因为如果所有返回的列都不在 group by 列表中或不在聚合函数内,它将不会运行。
我确信您可以将建议的数据源提供给您的数据网格,并且在某些 ItemDataBound 或类似事件期间,您可以将这些“1”成员标记更改为自定义字符串或带有“YES”或任何此类内容的图像。但是为了让这个工作正常,你的 databrid 不能使用硬编码的列名,并且能够从实际结果集中动态加载它们。
我已经在 SQL Server 2008 R2 上测试了我的查询。让我知道这是否是一个可接受的解决方案,以便我可以停止调整它。
HTH