【问题标题】:How to convert many-to-many entity relationship to tabular view in SQL?如何在 SQL 中将多对多实体关系转换为表格视图?
【发布时间】:2017-02-17 11:47:31
【问题描述】:

我需要帮助。我创建了一个表Users(列UserIDUserName)和一个表Project(列ProjectIDProjectName)和一个显示项目名称和用户名的桥接表。

每个项目有多个用户,每个用户可以在多个项目中。

桥接表如下所示:

是否可以制作这样的日期视图以及如何制作?

请注意,项目和用户名不是固定的,它们是动态的,它们是从 VB.NET 中的表单添加的。

【问题讨论】:

  • @michael raouf 你有定义的列数吗?即一个项目最多可以有多少用户?
  • 没有最大用户我需要是动态的,我认为这不是逻辑但我正在尝试它是否可用
  • 我只想简单地查看一个项目中的所有用户

标签: sql sql-server vb.net visual-studio many-to-many


【解决方案1】:

我可以提出以下解决方案(请不要太严格地判断,这只是一个想法):与其在第一行中使用虚拟的“用户名”作为列名,为什么不放真实的用户名并同意/每个用户/项目的行/列交叉处没有标记。见下图。这是各种成员表或玩家评分表中的常见视图类型(但它们在垂直和水平方向上具有相同的名称)。

我已插入测试成员记录,因此您可以看到 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

【讨论】:

    【解决方案2】:

    谢谢你们,我通过从组合框中选择项目名称找到了其他解决方案,并在表格中显示了他们在此项目中的用户名称,它看起来不像我在第一个中想要的,但这个解决方案更容易:D 再次感谢您

    【讨论】:

    • 感谢您的反馈!请注意,将来,如果您需要将行转换为列,请使用 PIVOT 子句并在此基础上进行构建。
    【解决方案3】:

    我在 SQL Server 中使用您显示的条目创建了一个表,并使用以下代码创建了一个 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:迈克尔、山姆、马克
    C#:山姆,马克
    Joomla:马克

    您只需要修改方法以根据需要显示输出。

    【讨论】:

    • 谢谢 Andrew,我看到你使用 VB.net 来获取输出,我正在搜索通过 SQL Query 将其加载到数据表中,然后将此数据表添加到 datagridview 所有这一切对我来说很容易做到,但只想知道它可以直接在 sql 中作为查询吗?
    • @michaelraouf 请编辑您的问题,询问您真正想问的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2013-11-10
    • 2012-08-22
    相关资源
    最近更新 更多