Мы можем использовать динамический sql для генерации сводного запроса с необходимыми столбцами и его выполнения.
Примечание: я использую NULL вместо '0' в пропущенных столбцах, чтобы не превышать допустимый максимальный разреженный размер данных в 8023 байта.
Если столбцы a, b, c ... AA из таблицы1:
- int: он будет поддерживать около 800 полей со значением 1, а остальные - нулевые
- бит: он будет поддерживать около 1142 полей со значением 1, а остальные - нулевые (если смотреть по вашему примеру, это лучший тип данных)
Чтобы проверить, будет ли работать этот скрипт, запустите следующий запрос, чтобы проверить, меньше ли поля, разрешенные типом.
~~~~
SELECT MAX([fields])
FROM (SELECT [fields] = COUNT(DISTINCT [category]) FROM [table2] GROUP BY [id]) AS [t]
~~~~
Отредактировано:
- процесс для партии размером 10000
- предполагает, что любой идентификатор в таблице2 существует в таблице1
~~~~
DECLARE @target_schema_name SYSNAME = N'dbo'; -- Modify if necessary
DECLARE @target_table_name SYSNAME = N'table1'; -- Modify if necessary
DECLARE @target_table_identifier SYSNAME = N'id'; -- Modify if necessary
DECLARE @source_schema_name SYSNAME = N'dbo'; -- Modify if necessary
DECLARE @source_table_name SYSNAME = N'table2'; -- Modify if necessary
DECLARE @source_table_identifier SYSNAME = N'id'; -- Modify if necessary
DECLARE @source_table_pivoter SYSNAME = N'category'; -- Modify if necessary
DECLARE @source_table_subquery_columns NVARCHAR(MAX) =
+ '[src].' + QUOTENAME(@source_table_identifier)
+ ','
+ '[src].' + QUOTENAME(@source_table_pivoter)
+ ','
+ '[auxiliar] = 1';
DECLARE @columns TABLE([name] SYSNAME);
INSERT INTO @columns ([name])
SELECT [c].[name]
FROM [sys].[schemas] AS [s]
INNER JOIN [sys].[tables] AS [t]
ON ([s].[schema_id] = [t].[schema_id])
INNER JOIN [sys].[columns] AS [c]
ON ([t].[object_id] = [c].[object_id])
WHERE (1 = 1)
AND ([s].[name] = @target_schema_name)
AND ([t].[name] = @target_table_name)
AND ([c].[name] <> @target_table_identifier)
AND ([c].[is_column_set] <> 1);
DECLARE @target_table_pivot_columns NVARCHAR(MAX) = NULL;
DECLARE @target_table_insert_columns NVARCHAR(MAX) = NULL;
DECLARE @source_table_insert_columns NVARCHAR(MAX) = NULL;
SELECT
@target_table_pivot_columns = IIF(@target_table_pivot_columns IS NULL, '', @target_table_pivot_columns + ',') + QUOTENAME([c].[name])
,@source_table_insert_columns = IIF(@source_table_insert_columns IS NULL, '', @source_table_insert_columns + ',') + QUOTENAME([c].[name]) --+ ' = ISNULL(' + QUOTENAME([c].[name]) + ', 0)'
FROM @columns AS [c];
SET @target_table_insert_columns = QUOTENAME(@target_table_identifier) + ',' + @target_table_pivot_columns;
SET @source_table_insert_columns = QUOTENAME(@source_table_identifier) + ',' + @source_table_insert_columns;
DECLARE @command NVARCHAR(MAX);
DECLARE @batch_min INT;
DECLARE @batch_max INT;
CREATE TABLE #ids ([id] INT, [batch] INT);
SET @command = '
INSERT INTO #ids ([id], [batch])
SELECT DISTINCT ' + QUOTENAME(@source_table_identifier) + ', (ROW_NUMBER() OVER (ORDER BY (SELECT 1)) - 1) / 10000
FROM ' + QUOTENAME(@source_schema_name) + '.' + QUOTENAME(@source_table_name) + ';
';
EXECUTE (@command);
SET @batch_min = 0;
SET @batch_max = (SELECT MAX([batch]) FROM #ids);
WHILE @batch_min <= @batch_max
BEGIN
SET @command = '
INSERT INTO ' + QUOTENAME(@target_schema_name) + '.' + QUOTENAME(@target_table_name) + '(' + @target_table_insert_columns + ')
SELECT ' + @source_table_insert_columns + '
FROM
(
SELECT ' + @source_table_subquery_columns + '
FROM ' + QUOTENAME(@source_schema_name) + '.' + QUOTENAME(@source_table_name) + ' AS [src]
INNER JOIN #ids AS [ids]
ON ([src].' + QUOTENAME(@source_table_identifier) + ' = [ids].[id])
WHERE (1 = 1)
AND ([ids].[batch] = ' + CONVERT(VARCHAR(11), @batch_min) + ')
) AS [src]
PIVOT (MAX([auxiliar]) FOR [category] IN (' + @target_table_pivot_columns + ')) AS [pvt]
';
EXECUTE (@command);
SET @batch_min += 1;
END
~~~~