Соедините две таблицы, затем транспонируйте строки из одной таблицы в качестве имен столбцов - PullRequest
2 голосов
/ 19 октября 2019

Я пытаюсь объединить две таблицы

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  

и затем транспонировать строки данных (из Name в таблицу 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

Правильно ли я использую пивот в этом сценарии?

1 Ответ

1 голос
/ 19 октября 2019

Рассмотрим ранжирование с 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 demo

Для динамического запроса создайте строку @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 demo

...