【问题标题】:Transpose rows and columns with no aggregate转置没有聚合的行和列
【发布时间】:2014-01-08 15:06:10
【问题描述】:

我有以下数据集

Account Contact

1   324324324
1   674323234
2   833343432
2   433243443
3   787655455
4   754327545
4   455435435
5   543544355
5   432455553
5   432433242
5   432432432

我想输出如下:

Account Contact1    Contact2    Contact3    Contact4

1   324324324   674323234       
2   833343432   433243443       
3   787655455           
4   754327545   455435435       
5   543544355   432455553   432433242   432432432

问题还在于我的帐户数量和联系人数量不固定

【问题讨论】:

    标签: sql-server sql-server-2008 pivot


    【解决方案1】:

    如果您要应用 PIVOT 函数,您将需要使用聚合函数来获取结果,但您还需要使用像 row_number() 这样的窗口函数来为每个联系人生成唯一的序列帐户。

    首先,您将查询您的数据,类似于:

    select account, contact,
      'contact'
        + cast(row_number() over(partition by account
                                  order by contact) as varchar(10)) seq
    from yourtable
    

    SQL Fiddle with Demo。这将创建一个具有唯一序列的新列:

    | ACCOUNT |   CONTACT |      SEQ |
    |---------|-----------|----------|
    |       1 | 324324324 | contact1 |
    |       1 | 674323234 | contact2 |
    

    如果您的列数有限,那么您可以对查询进行硬编码:

    select account,
      contact1, contact2, contact3, contact4
    from 
    (
      select account, contact,
        'contact'
          + cast(row_number() over(partition by account
                                    order by contact) as varchar(10)) seq
      from yourtable
    ) d
    pivot
    (
      max(contact)
      for seq in (contact1, contact2, contact3, contact4)
    ) piv;
    

    SQL Fiddle with Demo

    如果您有未知数量的列,那么您将不得不使用动态 SQL:

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT ',' + QUOTENAME(seq) 
                        from
                        (
                          select 'contact'
                                  + cast(row_number() over(partition by account
                                                            order by contact) as varchar(10)) seq
                          from yourtable
                        ) d
                        group by seq
                        order by seq
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT account, ' + @cols + ' 
                from 
                (
                    select account, contact,
                      ''contact''
                        + cast(row_number() over(partition by account
                                                  order by contact) as varchar(10)) seq
                    from yourtable
                ) x
                pivot 
                (
                    max(contact)
                    for seq in (' + @cols + ')
                ) p '
    
    execute sp_executesql @query;
    

    SQL Fiddle with Demo。两者都会给你一个结果:

    | ACCOUNT |  CONTACT1 |  CONTACT2 |  CONTACT3 |  CONTACT4 |
    |---------|-----------|-----------|-----------|-----------|
    |       1 | 324324324 | 674323234 |    (null) |    (null) |
    |       2 | 433243443 | 833343432 |    (null) |    (null) |
    |       3 | 787655455 |    (null) |    (null) |    (null) |
    |       4 | 455435435 | 754327545 |    (null) |    (null) |
    |       5 | 432432432 | 432433242 | 432455553 | 543544355 |
    

    【讨论】:

      【解决方案2】:

      只是生成动态PIVOT的方式略有不同:

      DECLARE @c INT;
      
      SELECT TOP 1 @c = COUNT(*) 
        FROM dbo.YourTable
        GROUP BY Account 
        ORDER BY COUNT(*) DESC;
      
      DECLARE @dc1 NVARCHAR(MAX) = N'', @dc2 NVARCHAR(MAX) = N'', @sql NVARCHAR(MAX);
      
      SELECT @dc1 += ',Contact' + RTRIM(i), @dc2 += ',[Contact' + RTRIM(i) + ']'
        FROM (SELECT TOP (@c) i = number + 1 
        FROM master.dbo.spt_values WHERE type = N'P' ORDER BY number) AS x;
      
      SET @sql = N'SELECT Account ' + @dc1 + 
        ' FROM (SELECT Account, Contact, rn = ''Contact'' 
            + RTRIM(ROW_NUMBER() OVER (PARTITION BY Account ORDER BY Contact))
          FROM dbo.YourTable) AS src PIVOT (MAX(Contact) FOR rn IN (' 
            + STUFF(@dc2, 1, 1, '') + ')) AS p;';
      
      EXEC sp_executesql @sql;
      

      SQLiddle demo

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-22
        • 2015-06-09
        • 1970-01-01
        • 1970-01-01
        • 2013-01-29
        • 1970-01-01
        • 2023-04-08
        相关资源
        最近更新 更多