如何从表中插入数据并对其进行透视

时间:2018-09-12 20:25:28

标签: sql sql-server pivot sql-server-2014 sql-insert

我有2张桌子。

Table1大约有2k列,如下所示:

Id  A B C D E F G H...........................................AA
1
2

Table2有2列,看起来像:

Id Category
1  A
1  C
1  AA
2  B 
2  D  

我想在table1中插入并旋转table2的数据

表1最终应该看起来像

Id  A B C D E F G H...........................................AA
1   1 0 1 0 0 0 0 0...........................................0 
2   0 1 1 0 0 0 0 0...........................................0

我不确定如何在sql中执行此操作。非常感谢您提供任何帮助。

2 个答案:

答案 0 :(得分:0)

关于sqlivot命令的绝对愚蠢的事情是,您必须知道/列出每一列。由于某种原因,Microsoft Access具有一种非常优雅的方式来旋转所有内容。因此,我什至不用费心使用透视命令。 Intead只是做大量案例和分组依据

select 
id, 
sum(case when category = 'A' then 1 else 0 end) as 'A',
sum(case when category = 'B' then 1 else 0 end) as 'B',
sum(case when category = 'C' then 1 else 0 end) as 'C',
etc...
from table2
group by id

我同意其他一些评论。如果您的情况允许,请考虑使用具有出色的透视/不透视命令的Excel PowerQuery或使用具有透视/转置工具的基于gui的工具,如Alteryx。快得多!

答案 1 :(得分:0)

我们可以使用动态sql生成具有必要列的数据透视查询并执行。

注意:我在缺失列中使用NULL而不是'0'来保持在8023 byes的允许最大稀疏数据大小之下。

如果table1中的a,b,c ... AA列为:

  • int:它将支持大约800个值为1的字段,其他字段为空
  • 位:它将支持大约1142个值为1的字段,其他字段为null(从您的样本来看,这是更好的数据类型)

要检查此脚本是否可以运行,请运行下一个查询以检查是否小于类型所允许的字段。

~~~~

SELECT MAX([fields])
FROM (SELECT [fields] = COUNT(DISTINCT [category]) FROM [table2] GROUP BY [id]) AS [t]

~~~~

编辑:

  • 批量为10000个的过程。
  • 假定table2中的任何id在table1中存在

~~~~

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

~~~~