Преобразовать таблицу с неизвестной структурой в ключ / значение - PullRequest
0 голосов
/ 08 мая 2019

Данные отчетов, которые мы получаем от аналитиков, представлены в формате таблицы с произвольной структурой.Все, что мы знаем, это то, что в каждой строке есть столбец CustomerId.Но о других мы не знаем и можем каждый раз меняться.

Система назначения, которая получает эти данные, работает только в формате ключ / значение, поэтому нам необходимо преобразовать таблицы отчета в ключ / значение.

Так, если, например, исходная таблица отчета имеет следующую структуру:

CREATE TABLE [dbo].[SampleSourceTable](
    [CustomerId] [bigint] NULL,
    [Column1] [nchar](10) NULL,
    [Column2] [int] NULL,
    [Column3] [datetime] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[SampleSourceTable] ([CustomerId], [Column1], [Column2], [Column3]) VALUES (1, N'aaa', 123, CAST(N'2019-01-01T00:00:00.000' AS DateTime))
GO
INSERT [dbo].[SampleSourceTable] ([CustomerId], [Column1], [Column2], [Column3]) VALUES (2, N'bbb', 456, CAST(N'2018-01-01T00:00:00.000' AS DateTime))
GO

enter image description here

Мы хотели бы, чтобы эти данные были преобразованыв следующую структуру:

CREATE TABLE [dbo].[SampleDestinationTable](
    [CustomerId] [bigint] NULL,
    [Attribute] [nvarchar](255) NULL,
    [Value] [nvarchar](max) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
INSERT [dbo].[SampleDestinationTable] ([CustomerId], [Attribute], [Value]) VALUES (1, N'Column1', N'aaa')
GO
INSERT [dbo].[SampleDestinationTable] ([CustomerId], [Attribute], [Value]) VALUES (1, N'Column2', N'123')
GO
INSERT [dbo].[SampleDestinationTable] ([CustomerId], [Attribute], [Value]) VALUES (1, N'Column3', N'2019-01-01 00:00:00.000')
GO
INSERT [dbo].[SampleDestinationTable] ([CustomerId], [Attribute], [Value]) VALUES (2, N'Column1', N'bbb')
GO
INSERT [dbo].[SampleDestinationTable] ([CustomerId], [Attribute], [Value]) VALUES (2, N'Column2', N'456')
GO
INSERT [dbo].[SampleDestinationTable] ([CustomerId], [Attribute], [Value]) VALUES (2, N'Column3', N'2018-01-01 00:00:00.000')
GO

enter image description here

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

Сначала я думал о том, чтобы пройти каждую строку с помощью курсора, а затем с помощью вложенного курсора пройти через все столбцы в этой строке.Но, по-видимому, не существует способа обработки строки с неизвестной структурой с использованием курсоров .Итак, на данный момент мне интересно, возможно ли это с помощью PIVOT / UNPIVOT.Но опять же, я думаю, что им также требуется список столбцов.

Я использую SQL Server 2017.

Как преобразовать данные с неизвестной структурой?

Ответы [ 2 ]

2 голосов
/ 08 мая 2019

Один из возможных подходов - генерировать динамический оператор, используя информацию из INFORMATION_SCHEMA.COLUMNS:

-- Declarations
DECLARE @stm nvarchar(max)

-- Dynamic part 
SELECT 
    @stm = STUFF((
        SELECT CONCAT(
            N' UNION ALL SELECT CustomerID, ''', 
            [COLUMN_NAME],
            N''' AS [Attribute], CONVERT(nvarchar(max), ',
            QUOTENAME([COLUMN_NAME]),
            CASE 
                WHEN DATA_TYPE = 'datetime' THEN N', 121'
                -- Add additional conversion rules for other data types
                ELSE N''
            END,
            N') AS [Value]', 
            N' FROM [SampleSourceTable]'
        )
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE (TABLE_NAME = 'SampleSourceTable') AND (COLUMN_NAME <> 'CustomerId')
    FOR XML PATH('')
    ), 1, 11, N'')

-- Whole statement and execution
SET @stm = @stm + N'ORDER BY CustomerID'
PRINT @stm 
EXEC (@stm)

Выход:

CustomerID  Attribute   Value
1           Column1     aaa       
1           Column2     123
1           Column3     2019-01-01 00:00:00.000
2           Column3     2018-01-01 00:00:00.000
2           Column2     456
2           Column1     bbb       
0 голосов
/ 08 мая 2019

Ах, вы открыли второй вопрос, я просто поместил ответ на ваш первый ...

Так что я буду использовать это место, чтобы предоставить ту же технику, что и мой другой ответ, но без необходимости динамическисоздал SQL.Попробуйте это:

DECLARE @xml XML =(SELECT TOP 10 o.object_id,o.* FROM sys.objects o FOR XML RAW, ELEMENTS XSINIL);

SELECT r.value('*[1]/text()[1]','nvarchar(max)') AS RowID
        ,c.value('local-name(.)','nvarchar(max)') AS ColumnKey
        ,c.value('text()[1]','nvarchar(max)') AS ColumnValue
FROM @xml.nodes('/row') A(r)
CROSS APPLY A.r.nodes('*[position()>1]') B(c);

Первый столбец набора будет возвращен как RowID .Если это не правильно, вы можете форсировать это, выполнив то же самое, что я сделал выше, чтобы заставить o.object_id в первую очередь.Все столбцы вашего результата будут возвращены как EAV.

Часть результата

+-------+---------------------+-------------------------+
| RowID | ColumnKey           | ColumnValue             |
+-------+---------------------+-------------------------+
| 3     | name                | sysrscols               |
+-------+---------------------+-------------------------+
| 3     | object_id           | 3                       |
+-------+---------------------+-------------------------+
| 3     | principal_id        | NULL                    |
+-------+---------------------+-------------------------+
| 3     | schema_id           | 4                       |
+-------+---------------------+-------------------------+
| 3     | parent_object_id    | 0                       |
+-------+---------------------+-------------------------+
| 3     | type                | S                       |
+-------+---------------------+-------------------------+
| 3     | type_desc           | SYSTEM_TABLE            |
+-------+---------------------+-------------------------+
| 3     | create_date         | 2017-08-22T19:38:02.860 |
+-------+---------------------+-------------------------+
| 3     | modify_date         | 2017-08-22T19:38:02.867 |
+-------+---------------------+-------------------------+
| 3     | is_ms_shipped       | 1                       |
+-------+---------------------+-------------------------+
| 3     | is_published        | 0                       |
+-------+---------------------+-------------------------+
| 3     | is_schema_published | 0                       |
+-------+---------------------+-------------------------+
| 5     | name                | sysrowsets              |
+-------+---------------------+-------------------------+
| ... more rows ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...