【问题标题】:SQL Pivot TableSQL 数据透视表
【发布时间】:2009-11-03 19:26:53
【问题描述】:

我有一个包含以下数据的 SQL 视图:

ID   ClassName    Description   Flags
1    Class1         Desc1        F1
2    Class1         Desc1        F2
3    Class1         Desc1        F3
4    Class1         Desc1        F4
5    Class2         Desc2        F2
6    Class2         Desc2        F6
7    Class3         Desc3        F1
8    Class4         Desc4        F8

我想要这样的结果:

ClassName    Description    F1   F2  F3  F4  F6   F8
Class1         Desc1         T    T  T    T   F   F
Class2         Desc2         F    T  F    F   T   F
Class3         Desc3         T    F  F    F   F   F
Class4         Desc4         F    F  F    F   F   T

我试图查找 Pivot 示例,但所有这些示例都用于 SUM 或其他聚合函数。不确定其中任何一个是否会起作用,因为我也没有这样做。

【问题讨论】:

  • 什么版本的 SQL Server,你尝试过什么?

标签: sql sql-server tsql pivot


【解决方案1】:

Henry Fao 走在正确的轨道上 - 但您必须使用 group by 将行“展平”。

选择 ClassName 作为 ClassName, 选择 Description 作为 Description , 合并(max(F1), 'F') 作为 F1 , 合并(max(F2), 'F') 作为 F2 , ETC 从 ( 选择类名,描述 , 如果 flags = 'F1' then 'T' else null end as F1 , 如果 flags = 'F2' then 'T' else null end as F2 等等 来自 tbl ) 作为 t 按类名、描述分组

每组的 F1 列中应该只有一个“T”。其他行在 T1 列中将为空。 max() 函数忽略空值并返回 'T' - 如果有的话。

【讨论】:

    【解决方案2】:

    选择类名、描述、flags = 'F1' then 'T' else 'F' end F1、case when flags = 'F2' then 'T' else 'F' end F2, ...

    【讨论】:

      【解决方案3】:

      我相信 MS SQL Server 支持数据透视表,但我不知道该怎么做。当我必须在 MySQL 中透视数据时,我使用 Sum 和 Case。但是,这仅在您事先知道列名将是什么时才有效。我可以这样做:

      Select
      X.ClassName,
      X.Description,
      Case When X.F1 = 1 Then 'T' Else 'F' End As `F1`,
      Case When X.F2 = 1 Then 'T' Else 'F' End As `F2`
      /* etc. for the rest of your Flags*/
      FROM (
          Select
          ClassName,
          Description,
          Sum(Case When Flags = 'F1' Then 1 Else 0 End) As `F1`,
          Sum(Case When Flags = 'F2' Then 1 Else 0 End) As `F2`
          /* etc. for the rest of your Flags*/
          From 
          ClassTable
          Group By
          ClassTable.ClassName
          ) X
      

      在上面的代码中,子查询会产生你想要的输出,除了你会得到 1 和 0(假设你从不重复一个类的标志)。语句顶部的“主”查询只是将 1 和 0 转换为 T 和 F。

      同样,这要求您知道列名是什么,但这是我知道如何在您使用的 SQL 语言中不内置“PIVOT”的情况下做到这一点的唯一方法。 MS SQL 可能有一个 PIVOT 内置,所以你可能想挖掘一下。

      【讨论】:

      • 我不会知道我的标志是什么,因为最终用户可以添加、更新或删除标志并与他们想要的任何类进行关联(例如,用户可以添加一个新标志,比如 F101 或重命名现有标志F1 到 F01)。我正在使用 SQL Express 2005
      • 这是一个讨厌的 hack:如果你有能力在运行时生成 SQL,你可以在你的表中查询所有可用的 Flag 名称,然后生成带有列的 SQL 语句(Sum(Case When Flags ...) 自动从代码生成。这让我觉得它很肮脏,但如果你有代码可以使用它会起作用。
      【解决方案4】:

      这不是很漂亮,我通常不喜欢动态创建的 SQL,但是由于标志列表未知,我不确定你还能怎么做。此外,您说得对,因为 PIVOT 命令需要一个聚合,所以我只使用了 MAX。是的,这有点骇人听闻,但它确实完成了工作,并且会随着新标志的添加而扩展。我认为这应该适用于 2005/2008 版本的 SQL-SERVER。我不确定 2003 年是否有 XML PATH 命令。

      Declare @ColumnsIn varchar(max)
      Declare @ColumnsIsNull varchar(max)
      Declare @sql varchar(max)
      
      Select @ColumnsIn = Stuff((Select Distinct ',[' + Flags + ']' From Classes For XML PATH('')),1,1,'')
      Select @ColumnsIsNull = Stuff((Select Distinct ', IsNull([' + Flags + '], ''F'') as [' + Flags + ']' From Classes For XML PATH('')),1,1,'')
      
      Set @sql = '
          Select 
              ClassName,
              Description,
              ' + @ColumnsIsNull + '
          FROM
          (
              Select
                  Classes.ClassName,
                  Classes.Description,
                  Classes.Flags,
                  ''T'' as HasFlag
              From
                  Classes
          ) as Sub1
          Pivot (Max(HasFlag) For Flags in (' + @ColumnsIn + ')) as Sub2'
      
      Execute(@sql)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-03
        • 2017-11-25
        • 2012-02-22
        相关资源
        最近更新 更多