SQL 如何将多对多实体关系转换为表格视图?
How to convert many-to-many entity relationship to tabular view in SQL?
拜托,我需要帮助。我创建了一个 table Users
(列 UserID
、UserName
)和一个 table Project
(列 ProjectID
、ProjectName
) 和一个显示项目名称和用户名的桥 table。
每个项目有多个用户,每个用户可以在多个项目中。
桥 table 看起来像这样:
是否可以像这样制作日期视图?如何制作?
请注意,项目和用户名不是固定的,它们是动态的,它们是从 VB.NET 中的表单添加的。
我使用您显示的条目在 SQL 服务器中创建了一个 table,并使用以下代码创建了一个 VB.NET 控制台应用程序:
Option Infer On
Imports System.Data.SqlClient
Module Module1
Sub Main()
Dim csb As New SqlConnectionStringBuilder With {.DataSource = ".\SQLEXPRESS", .InitialCatalog = "testing", .IntegratedSecurity = True}
Dim projectsUsers As New Dictionary(Of String, List(Of String))
Using sqlConn As New SqlConnection(csb.ConnectionString)
Dim sql = "SELECT [project], [user] FROM ProjectUser"
Using sqlCmd As New SqlCommand(sql, sqlConn)
sqlConn.Open()
Using rdr = sqlCmd.ExecuteReader()
If rdr.HasRows Then
While rdr.Read()
Dim project = rdr.GetString(0)
Dim user = rdr.GetString(1)
If projectsUsers.ContainsKey(project) Then
projectsUsers(project).Add(user)
Else
projectsUsers.Add(project, New List(Of String) From {user})
End If
End While
End If
End Using
End Using
End Using
' adjust output as required
For Each kvp In projectsUsers
Console.WriteLine(kvp.Key & ": " & String.Join(", ", kvp.Value))
Next
Console.ReadLine()
End Sub
End Module
得到这个输出:
SQL: Michael, Sam, Mark
C#: Sam, Mark
Joomla: Mark
您只需修改方法即可根据需要显示输出。
我可以提出以下解决方案(请不要过于严格地判断,这只是一个想法):与其在第一行中使用虚拟 'Username' 作为列名,不如将真实用户放在那里每个 user/project 的 row/column 十字路口都有 yes/no 标记。见下图。这是各种会员表或玩家评分表中的常见视图类型(但它们在纵向和横向上具有相同的名称)。
我插入了测试成员记录,因此您可以看到 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
请注意,由于您的要求是拥有 projects/users 的动态列表,因此我不得不使用动态 sql 为 T-SQL PIVOT 创建动态列列表,这通常可以正常工作有 hardcoded/static values/column 个名字。
请注意,在使用的数据透视块中还有一个 min(IsMember) 技巧,因为数据透视需要包含一些聚合函数,但我们不能使用 min(UserName),因为它实际上 return 中的最小名称一组特定的项目成员名称。
@pivotColNamesMin 是另一个技巧,现在用于 GROUP BY 因为它不会 运行 如果所有 returned 列不在 group by 列表中或不在聚合函数内。
我确定您可以将建议的数据源提供给您的数据网格,并且在某些 ItemDataBound 或类似事件期间,您可以将这些“1”成员标记更改为带有 'YES' 或任何类似内容的自定义字符串或图像种类。但是为了让它工作,你的数据桥不能使用硬编码的列名并且能够从实际结果集中动态加载它们。
我已经在 SQL Server 2008 R2 上测试了我的查询。让我知道这是否是一个可接受的解决方案,以便我可以停止调整它。
HTH
谢谢你们,我通过 select 组合框中的项目名称找到了其他解决方案,并在 table 中显示了他们在该项目中的用户名称,这看起来不像什么我想要第一个,但这个解决方案更简单 :D 再次感谢你
拜托,我需要帮助。我创建了一个 table Users
(列 UserID
、UserName
)和一个 table Project
(列 ProjectID
、ProjectName
) 和一个显示项目名称和用户名的桥 table。
每个项目有多个用户,每个用户可以在多个项目中。
桥 table 看起来像这样:
是否可以像这样制作日期视图?如何制作?
请注意,项目和用户名不是固定的,它们是动态的,它们是从 VB.NET 中的表单添加的。
我使用您显示的条目在 SQL 服务器中创建了一个 table,并使用以下代码创建了一个 VB.NET 控制台应用程序:
Option Infer On
Imports System.Data.SqlClient
Module Module1
Sub Main()
Dim csb As New SqlConnectionStringBuilder With {.DataSource = ".\SQLEXPRESS", .InitialCatalog = "testing", .IntegratedSecurity = True}
Dim projectsUsers As New Dictionary(Of String, List(Of String))
Using sqlConn As New SqlConnection(csb.ConnectionString)
Dim sql = "SELECT [project], [user] FROM ProjectUser"
Using sqlCmd As New SqlCommand(sql, sqlConn)
sqlConn.Open()
Using rdr = sqlCmd.ExecuteReader()
If rdr.HasRows Then
While rdr.Read()
Dim project = rdr.GetString(0)
Dim user = rdr.GetString(1)
If projectsUsers.ContainsKey(project) Then
projectsUsers(project).Add(user)
Else
projectsUsers.Add(project, New List(Of String) From {user})
End If
End While
End If
End Using
End Using
End Using
' adjust output as required
For Each kvp In projectsUsers
Console.WriteLine(kvp.Key & ": " & String.Join(", ", kvp.Value))
Next
Console.ReadLine()
End Sub
End Module
得到这个输出:
SQL: Michael, Sam, Mark
C#: Sam, Mark
Joomla: Mark
您只需修改方法即可根据需要显示输出。
我可以提出以下解决方案(请不要过于严格地判断,这只是一个想法):与其在第一行中使用虚拟 'Username' 作为列名,不如将真实用户放在那里每个 user/project 的 row/column 十字路口都有 yes/no 标记。见下图。这是各种会员表或玩家评分表中的常见视图类型(但它们在纵向和横向上具有相同的名称)。
我插入了测试成员记录,因此您可以看到 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
请注意,由于您的要求是拥有 projects/users 的动态列表,因此我不得不使用动态 sql 为 T-SQL PIVOT 创建动态列列表,这通常可以正常工作有 hardcoded/static values/column 个名字。
请注意,在使用的数据透视块中还有一个 min(IsMember) 技巧,因为数据透视需要包含一些聚合函数,但我们不能使用 min(UserName),因为它实际上 return 中的最小名称一组特定的项目成员名称。
@pivotColNamesMin 是另一个技巧,现在用于 GROUP BY 因为它不会 运行 如果所有 returned 列不在 group by 列表中或不在聚合函数内。
我确定您可以将建议的数据源提供给您的数据网格,并且在某些 ItemDataBound 或类似事件期间,您可以将这些“1”成员标记更改为带有 'YES' 或任何类似内容的自定义字符串或图像种类。但是为了让它工作,你的数据桥不能使用硬编码的列名并且能够从实际结果集中动态加载它们。
我已经在 SQL Server 2008 R2 上测试了我的查询。让我知道这是否是一个可接受的解决方案,以便我可以停止调整它。
HTH
谢谢你们,我通过 select 组合框中的项目名称找到了其他解决方案,并在 table 中显示了他们在该项目中的用户名称,这看起来不像什么我想要第一个,但这个解决方案更简单 :D 再次感谢你