Как SQL PIVOT для двух столбцов и с именами динамических c столбцов? - PullRequest
2 голосов
/ 10 апреля 2020

У меня есть пара ключей и набор строк для привязки к уникальному идентификатору (ApplicationId).

Данные будут выглядеть примерно так:

| ApplicationId | Key | Value | Date                  |
| 123           | A   | abc   | 2020-3-1 14:00:01.000 |
| 123           | B   | abd   | 2020-3-1 14:00:02.000 |
| 123           | C   | abe   | 2020-3-1 14:00:03.000 |
| 124           | A   | abf   | 2020-3-1 14:01:00.000 |
| 124           | D   | abg   | 2020-3-1 14:01:01.000 |

Конечный результат i ' m ищет вот что:

| ApplicationId | A   | A_Date                | B    | B_Date                | C    | C_Date                | D    | D_Date                |
| 123           | abc | 2020-3-1 14:00:01.000 | abd  | 2020-3-1 14:00:02.000 | abe  | 2020-3-1 14:00:03.000 | NULL | NULL                  |
| 124           | abf | 2020-3-1 14:01:00.000 | NULL | NULL                  | NULL | NULL                  | abg  | 2020-3-1 14:01:01.000 |

Ключи A, B, C, D неизвестны, поэтому жесткое кодирование имен столбцов невозможно.

Вот кое-что, что работает с одним PIVOT

IF OBJECT_ID('tempdb.dbo.#_BLAH') IS NOT NULL DROP TABLE #_BLAH

SELECT et.[ApplicationId] et.[Key], et.[Value], et.[Date]
INTO #_BLAH
FROM ExampleTbl et
WHERE et.[Date] > DATEADD(dd, -1, GetDate())

DECLARE @_cols AS NVARCHAR(MAX)
DECLARE @_sql  AS NVARCHAR(MAX)

SELECT 
    @_cols += QUOTENAME([Key]) + ','
FROM 
    #_BLAH
GROUP BY
    [Key];

SET @_cols = STUFF((SELECT ',' + QUOTENAME(T.[Key])
                    FROM #_BLAH AS T
                    GROUP BY T.[Key]
            FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')


set @_sql = 'SELECT [ApplicationId], ' + @_cols + '
    FROM ( SELECT * FROM #_BLAH) AS SRC
    PIVOT ( MAX([Value]) FOR [Key] IN (' + @_cols + ') ) AS p';

EXEC(@_sql)

До сих пор мне не удалось найти пример или статью, пытающуюся создать второй столбец динамического c и добавить значение, связанное с указанным c ключом. в моем примере.

Мой SQL выше выполнит sh создание нужной мне строки, за исключением нужного мне столбца #_Date.

Ответы [ 2 ]

2 голосов
/ 10 апреля 2020

Вы можете попробовать это

DECLARE @_cols AS NVARCHAR(MAX) =''
DECLARE @_sql  AS NVARCHAR(MAX)

SELECT 
    @_cols +=','+ QUOTENAME([Key]) + ','  + QUOTENAME([Key]+'_Date') 
FROM 
    (SELECT DISTINCT [Key] FROM ExampleTbl) T

SET @_cols = STUFF(@_cols,1,1,'')

set @_sql = 'SELECT * FROM (
    SELECT ApplicationId, [Key], Value FROM ExampleTbl
    UNION ALL
    SELECT ApplicationId, [Key] + ''_Date'' AS [Key], CONVERT(VARCHAR(30), [Date],121 ) AS Value FROM ExampleTbl
) SRC
    PIVOT (MAX(Value) FOR [Key] IN ('+@_cols +' )) AS PVT';

EXEC(@_sql)

Результат:

ApplicationId A       A_Date                      B          B_Date                     C            C_Date                    D       D_Date
------------- ------- --------------------------- ---------- -------------------------- ------------ ------------------------- ------- -------------------------
123           abc     2020-03-01 14:00:01.000     abd        2020-03-01 14:00:02.000    abe          2020-03-01 14:00:03.000   NULL    NULL
124           abf     2020-03-01 14:01:00.000     NULL       NULL                       NULL         NULL                      abg     2020-03-01 14:01:01.000
2 голосов
/ 10 апреля 2020

Попробуйте:

DROP TABLE IF EXISTS #DataSource;
DROP TABLE IF EXISTS #DataSourcePrepared;

CREATE TABLE #DataSource
(
    [ApplicationId] INT
   ,[Key] CHAR(1)
   ,[Value] VARCHAR(12)
   ,[Date] DATETIME2(0)
);

INSERT INTO #DataSource ([ApplicationId], [Key], [Value], [Date])
VALUES (123, 'A', 'abc', '2020-3-1 14:00:01.000')
      ,(123, 'B', 'abd', '2020-3-1 14:00:02.000')
      ,(123, 'C', 'abe', '2020-3-1 14:00:03.000')
      ,(124, 'A', 'abf', '2020-3-1 14:01:00.000')
      ,(124, 'D', 'abg', '2020-3-1 14:01:01.000');


CREATE TABLE #DataSourcePrepared
(
    [ApplicationId] INT
   ,[ColumnName] VARCHAR(32)
   ,[Value] VARCHAR(32)
)

INSERT INTO #DataSourcePrepared ([ApplicationId], [ColumnName], [Value])
SELECT [ApplicationId]
      ,[Key]
      ,[value] 
FROM #DataSource
UNION ALL
SELECT [ApplicationId]
      ,[Key] + '_Date'
      ,CONVERT(VARCHAR(19), [Date], 121)
FROM #DataSource;

DECLARE @DymanimcTSQLSatement NVARCHAR(MAX)
       ,@DynamicColumns NVARCHAR(MAX);

SET @DynamicColumns = STUFF
                      (
                        (
                            SELECT ',' + QUOTENAME([ColumnName])
                            FROM #DataSourcePrepared
                            GROUP BY [ColumnName]
                            ORDER BY [ColumnName]
                            FOR XML PATH(''), TYPE
                        ).value('.', 'NVARCHAR(MAX)')
                        ,1
                        ,1
                        ,''
                     );



SET @DymanimcTSQLSatement = N'
SELECT *
FROM #DataSourcePrepared
PIVOT
(
    MAX([value]) FOR [ColumnName] IN (' + @DynamicColumns +')
) PVT;';

EXECUTE sp_executesql @DymanimcTSQLSatement;

enter image description here

Вам просто нужно подготовить данные до фактического PIVOT. Также обратите внимание, что я упорядочиваю столбцы, когда строю динамическую часть c по name. В вашем реальном случае вы можете изменить это на что-то сложное.

...