【问题标题】:Converting 200+ rows to column in SQL Server using PIVOT使用 PIVOT 在 SQL Server 中将 200 多行转换为列
【发布时间】:2019-11-18 10:46:20
【问题描述】:

我已经做了一些研究,到目前为止,这对我来说很有意义:

Convert row value in to column in SQL server (PIVOT)

但是,我想知道是否有任何方法可以做到这一点,而不必一一声明所需的列,因为我有 200 多个列要检索。

下面是我作为桌子的一瞥:

ID   | Col_Name   | Col_Value    
------------------------------
1    | Item_Num   | 12345
2    | Item_Date  | 34567
3    | Item_Name  | 97454
4    | Item_App1  | 234567
5    | Item_App2  | 345678

请注意,我有 200 多个不同的 Col_Name 值,我希望它是列字段。

我现在正在使用这个,但只用于 5 列:

SELECT * FROM 
(
   SELECT [ID], [Col_Name], [Col_Value] 
   FROM myTable
) AS a 
PIVOT 
(
   MAX([Col_Value])
   FOR [Col_Name] in ([Item_Num], [Item_Date], [Item_Name], [Item_App1], [Item_App2])
) AS p 
ORDER BY [ID]

考虑到性能,有什么办法可以做到这一点?提前致谢。

【问题讨论】:

  • 如果您关心性能,请不要以这种格式存储您的数据。只需使用包含 200 多列的常规记录,每列一个。
  • 这只是您在使用 EAV 设计时会遇到的众多问题之一。事实上,您已经在示例数据中提供了一个 - 34567 是表中的有效“日期”,因为该列将允许该值按原样存储。
  • @GordonLinoff 我必须根据工作要求使用这种格式。
  • @SMor 同意 EAV。至于我发布的示例数据,对于造成的混乱表示歉意。这不是我的表格的确切数据,我只是输入了你看到的任何内容,只是为了展示一个例子。此外,整个表的值都是 nvarchar 数据类型。

标签: sql sql-server pivot


【解决方案1】:

可以使用动态sql创建col_name的列表:

declare @pivot_col varchar(max);
declare @sql       varchar(max);
select  @pivot_col = string_agg( cast(col_name as varchar(max)), ', ') within group ( order by col_name ) from ( select distinct col_name from tmp_table ) A;

set @sql = 'SELECT * 
            FROM   (
                      SELECT [ID], [Col_Name], [Col_Value] 
                      FROM tmp_table
                   ) AS a 
                   PIVOT 
                   (
                      MAX([Col_Value])
                      FOR [Col_Name] in (' +  @pivot_col + ' )
                   ) AS p 
                   ORDER BY [ID]';
exec ( @sql );

PIVOT / UNPIVOT 运算符建立在实体属性值模型 (EAV) 的原则之上。 EAV 模型背后的想法是您可以扩展数据库实体而无需执行数据库模式更改。因此,EAV 模型将实体的所有属性作为键/值对存储在一个表中。

如果这是您设计背后的想法,请使用我在上面发布的动态 sql 查询,否则请按照 Gordon 的建议,使用每个 id 包含 200 多列的常规记录。

您可以阅读有关 PIVOT / UNPIVOT 运算符的性能here

编辑: 对于 sql server 2016 版本:

declare @pivot_col varchar(max);
declare @sql       varchar(max);
select  @pivot_col = STUFF( (SELECT ',' + CAST(col_name AS VARCHAR(max)) AS [text()] FROM ( select distinct col_name from tmp_table ) A ORDER BY col_name FOR XML PATH('')), 1, 1, NULL);

set @sql = 'SELECT * 
            FROM   ( SELECT [ID], [Col_Name], [Col_Value] 
                     FROM tmp_table
                   ) AS a 
                   PIVOT 
                   (
                      MAX([Col_Value])
                      FOR [Col_Name] in (' +  @pivot_col + ' )
                   ) AS p 
                   ORDER BY [ID]';
exec ( @sql );

【讨论】:

  • 感谢您提供详细信息。但是,我使用的是 Sql Server 2016,我担心 sting_agg 在这里导致错误。 'string_agg' is not a recognized built-in function name.我也在查看你分享的链接,非常感谢。
  • 您可以使用 FOR XML PATH 作为 string_agg 函数的替代。我已编辑我的答案以包含新查询。希望对你有帮助
  • 我实际上从昨天开始就在玩这个,但是你在一行中让它变得非常简单!非常感谢。这就是我一直在寻找的。不过,我将不得不检查性能,因为查询完成执行需要将近 30 分钟。我只返回 800 多行,所以看起来 230 列让它变得很慢。
  • 嗨 Mohit,以防万一您也有时间研究一下:stackoverflow.com/questions/58949146/… 谢谢!
猜你喜欢
  • 1970-01-01
  • 2023-01-25
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多