首页 > 解决方案 > 连接两个表,然后将一个表中的行作为列名转置

问题描述

我正在尝试加入两个表

ColumnNames
ID  |Name        |Type    |Status |
-----------------------------------------------------
1   |Fullname    |varchar |Active
2   |Email       |varchar |Active  
3   |Position    |varchar |Active  
4   |Category    |varchar |Active
ColumnValues
ID  |ColumnNameID |value                |Status |
-----------------------------------------------------
1   |1            |Linda                |Active
2   |2            |linda@email.com      |Active  
3   |3            |Soft Eng.            |Active  
4   |4            |Cat 1                |Active
5   |1            |Remil                |Active
6   |2            |Remil@email.com      |Active  
7   |3            |Senior Soft Eng.     |Active  
8   |4            |Cat 2                |Active   
9   |1            |Ash                  |Active
10  |2            |ash@email.com        |Active  
11  |3            |Soft Eng.            |Active  
12  |4            |Cat 1                |Active  

然后将数据行(来自 ColumnNames 表上的名称)转换为列名。

现在,有人告诉我使用 Pivot。我已经成功地使用 pivot 来转置单个表中的行,但是我对如何从连接表中转置行感到困惑。

下面是我尝试过的代码,但它给了我一个错误,说列不存在

    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(ColumnName) 
                    from tm.ColumnName
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ColumnNameID, ' + @cols + ' from 
             (
                select i.ColumnNameID, i.ColumnValue
                from tm.ColumnValue i
                inner join tm.ColumnName a
                  on i.ColumnNameID = a.ColumnNameID
            ) x
            pivot 
            (
                max(ColumnNameID)
                for ColumnValue in (' + @cols + ')
            ) p '

execute(@query)

预期结果应该是

Fullname  |Email                 |Position             |Category |
--------------------------------------------------------------------
Linda     |linda@email.com       |Soft Eng.            |Cat 1
Remil     |Remil@email.com       |Senior Soft Eng.     |Cat 2
Ash       |ash@email.com         |Soft Eng.            |Cat 1

在这种情况下我是否正确使用了枢轴?

标签: sqlsql-serversql-server-2014

解决方案


考虑一个包含ROW_NUMBER每个列值类型(全名、电子邮件、职位、类别)的排名,INNER JOIN然后贯穿PIVOT。无需动态构建SQL:

SELECT [Fullname], [Email], [Position], [Category]
FROM (
    SELECT i.ColumnValue, a.[Name],
           ROW_NUMBER() OVER (PARTITION BY a.[Name] ORDER BY a.ColumnNameID) AS rn
    FROM ColumnValues i
    INNER JOIN ColumnNames a
      ON i.ColumnNameID = a.ColumnNameID
  ) tbl

PIVOT
   (MAX(ColumnValue) 
    FOR [Name] IN ([Fullname], [Email], [Position], [Category])
   ) pvt
ORDER BY rn

Rextester 演示

对于动态查询,构建一个@cols字符串以放置在数据透视查询的特定位置。

DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.[Name]) 
            FROM ColumnNames c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
             ,1,1,'')

SET @query = 'SELECT ' + @cols + '
                FROM (
                    SELECT i.ColumnValue, a.[Name],
                           ROW_NUMBER() OVER (PARTITION BY a.[Name] ORDER BY a.ColumnNameID) AS rn
                    FROM ColumnValues i
                    INNER JOIN ColumnNames a
                      ON i.ColumnNameID = a.ColumnNameID
                  ) tbl

                PIVOT
                   (MAX(ColumnValue) 
                    FOR [Name] IN (' + @cols + ')
                   ) pvt
                ORDER BY rn'

EXECUTE(@query)

Rextester 演示


推荐阅读