【问题标题】:How to convert rows to new columns in m to n relation ship table?如何将 m 到 n 关系表中的行转换为新列?
【发布时间】:2019-10-01 11:19:12
【问题描述】:

我需要一些帮助来解决一个问题。

我正在使用 SQL 开发一个 microsoft 数据库,并且我有一个与此类似的表:

|*Name*|*Permissions*|
|App1  |Permission 1 |
|App1  |Permission 2 |
|App1  |Permission 3 |
|App2  |Permission 1 |
|App2  |Permission 2 |
|App2  |Permission 3 |

所以这是一个 m 对 n 的关系,因为有多个权限分配给一个应用程序,但也有多个应用程序使用相同的权限。

我已经尝试过像这样使用 distinct 加入表格的方法:

select distinct apps1.name, apps2.permissions from Apps apps1
join Apps apps2
where apps2.name IN
(SELECT distinct name from Apps);

但它没有得到我正在寻找的结果。

我希望得到如下所示的结果:

|*Name*|*Permission1*|*Permission2*|*Permission3*|
|App1  |Permission 1 |Permission 2 |Permission 3 |
|App2  |Permission 1 |Permission 2 |Permission 3 |

有可能,应用程序获得了不同数量的权限,但如果是这样,这些空列用 NULL 值填充就可以了。

我希望你能帮助我。 如果需要任何进一步的信息,请写信给我。由于我是 StackOverflow 的新手,所以我不是写下问题的专业人士。

【问题讨论】:

    标签: sql tsql many-to-many multiple-columns


    【解决方案1】:

    您可以为此使用PIVOT 运算符。下面给出一个例子。

    CREATE TABLE #Permission
    (
     Name       VARCHAR(10)
    ,Permission VARCHAR(25)
    )
    
    INSERT INTO #Permission (Name, Permission) VALUES
    ('App1', 'Permission 1')
    ,('App1', 'Permission 2')
    ,('App1', 'Permission 3')
    ,('App2', 'Permission 1')
    ,('App2', 'Permission 2')
    ,('App2', 'Permission 3')
    ,('App3', 'Permission 2');
    
    
    SELECT * 
    FROM
        (
        SELECT Name, Permission FROM #Permission
        ) AS A
    PIVOT
        (
        MAX(Permission)
        FOR Permission IN ([Permission 1], [Permission 2], [Permission 3])
        ) AS PivotTable
    
    DROP TABLE #Permission;
    

    如果您有 n 个权限,那么您可能必须使用 dynamic pivoting

    【讨论】:

    • 我很确定,我们看到的 permissions 值只是变量值的占位符......这就是为什么我的 PIVOT-approach 创建了枢轴的每个应用的计数器中的列名...
    【解决方案2】:

    如果你有一个你关心的最大权限数(比如三个),你可以只使用条件聚合(或pivot):

    select a.name,
           max(case when seqnum = 1 then a.permission end) as permission_1,
           max(case when seqnum = 2 then a.permission end) as permission_2,
           max(case when seqnum = 3 then a.permission end) as permission_3
    from (select a.*,
                 row_number() over (partition by a.name order by a.name) as seqnum
          from apps a
         ) a
    group by a.name;
    

    如果不知道要返回多少列,则需要使用动态SQL,查询复杂一些。

    【讨论】:

    • 非常感谢您的快速回复,我需要将其调整为我的实际代码以检查它是否有效,但我无法弄清楚您使用“seqnum”做什么,请您帮忙解释一下?谢谢!
    • @s.binc 。 . .这是为权限分配一个数字所必需的,以便您可以将它们放在单独的列中。
    • 哦,我明白了,谢谢!不幸的是,order by (select null) 在我的数据库中不起作用,但我看不出我不应该按名称排序的原因。通过此更正,您的代码可以正常工作,谢谢!
    • @s.binc 。 . .这很奇怪。 SQL Server 支持order by (select null),但name 也可以。
    【解决方案3】:

    您可以使用PIVOT 进行此类查询:

    模拟您的问题的模型场景

    DECLARE @mockupTable TABLE([Name] VARCHAR(100),[Permissions] VARCHAR(100));
    INSERT INTO @mockupTable VALUES
     ('App1','Permission 1')
    ,('App1','Permission 2')
    ,('App1','Permission 3')
    ,('App2','Permission 1')
    ,('App2','Permission 2')
    ,('App2','Permission 3');
    

    --查询

    SELECT p.*
    FROM
    (
        SELECT t.*
              ,CONCAT('Permission',ROW_NUMBER() OVER(PARTITION BY t.[Name] ORDER BY t.[Permissions])) AS ColumnName
        FROM @mockupTable t
    ) tbl
    PIVOT
    (
        MAX(tbl.[Permissions]) 
        FOR tbl.ColumnName 
        IN(Permission1,Permission2,Permission3,Permission4 /*add as many as you need*/)
    ) p;
    

    简而言之:

    使用CONCATROW_NUMBER,我们可以创建一个值,以后可以将其用作枢轴的列名。

    【讨论】:

      【解决方案4】:

      你也可以试试这个 USING CTE

      ;with cte as (
      SELECT *
              ,ROW_NUMBER() over(partition by Name order by Permissions ) rn
      FROM YourTable
      ) 
      
      select      Name
                  ,MAX(case   when rn=1 then Permissions   end) Permission1
                  ,MAX(case   WHEN rn=2 then Permissions  end) Permission2
                  ,MAX(case   WHEN rn=3 then Permissions  end) Permission3
      FROM cte 
      group by Name
      

      【讨论】:

        猜你喜欢
        • 2021-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-12
        • 1970-01-01
        • 2020-10-03
        • 1970-01-01
        • 2014-11-08
        相关资源
        最近更新 更多