【问题标题】:SQL Server 2014 - displaying vertical data in horizontal formatSQL Server 2014 - 以水平格式显示垂直数据
【发布时间】:2017-07-22 23:05:48
【问题描述】:

这是我第一次在 stackoverflow 上发帖。我希望我做得对。

我有一个 SQL Server 2014 表,其中包含“垂直”数据,我需要将其旋转为具有多列的单个记录。 bluefeet 的回答 (SQL Server 2008 Vertical data to Horizontal) 几乎对我有用,但并不完全。我有临时表“#Columns”,其中包含可以根据数据更改的列名列表,以及包含我的数据的表“Transaction”。以下是#Columns 表的内容:

列名序列号
时间 1
2区
密度 3
参考索引 4
H2SO4 5
pH 6
尿素7
安 8
TN 9
比率 10
NH3 11
SpGr 12
Cl2 13
铁 14
毛 15
评论 99

以下是 Transaction 表中的相关数据:

TransactionId   SamplePoint_Id  SP_Chem_Id  EntryDate   Time    Chem_Id Value   Comment
636 18  108 7/19/2017   1219    21  1   NULL<br>
637 18  109 7/19/2017   1219    22  2   NULL<br>
638 18  110 7/19/2017   1219    28  3   NULL<br>
639 18  111 7/19/2017   1219    1   4   NULL<br>
640 18  112 7/19/2017   1219    51  693.51  NULL<br>
641 18  113 7/19/2017   1219    2   -442.68 NULL<br>
642 18  114 7/19/2017   1219    61  168.58  NULL<br>
643 18  115 7/19/2017   1219    52  -0.64   NULL<br>
644 18  116 7/19/2017   1219    4   0.1 NULL<br>
645 18  117 7/19/2017   1219    62  1.009   NULL<br>
646 18  NULL    7/19/2017   1219    54  5   NULL<br>
647 18  NULL    7/19/2017   1219    12  6   NULL<br>
648 18  NULL    7/19/2017   1219    33  7   NULL<br>
649 18  NULL    7/19/2017   1219    70  NULL    8.88889E+12<br>
650 18  NULL    7/19/2017   1219    71  NULL    NULL<br>
651 18  108 7/19/2017   1220    21  2   NULL<br>
652 18  109 7/19/2017   1220    22  3   NULL<br>
653 18  110 7/19/2017   1220    28  4   NULL<br>
654 18  111 7/19/2017   1220    1   5   NULL<br>
655 18  112 7/19/2017   1220    51  1413.51 NULL<br>
656 18  113 7/19/2017   1220    2   -729.68 NULL<br>
657 18  114 7/19/2017   1220    61  404.01  NULL<br>
658 18  115 7/19/2017   1220    52  -0.52   NULL<br>
659 18  116 7/19/2017   1220    4   0.07    NULL<br>
660 18  117 7/19/2017   1220    62  2.018   NULL<br>
661 18  NULL    7/19/2017   1220    12  7   NULL<br>
662 18  NULL    7/19/2017   1220    54  8   NULL<br>
663 18  NULL    7/19/2017   1220    33  9   NULL<br>
664 18  NULL    7/19/2017   1220    70  NULL    12341234<br>
665 18  NULL    7/19/2017   1220    71  NULL    NULL<br>

这是我的查询:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(ColumnName)
                    from #Columns
                    group by ColumnName, SeqNum
                    order by SeqNum
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

    set @query = N'SELECT ' + @cols + ' 
            from 
            (
                SELECT 
                c1.ColumnName,
                case when len(t.Comment) > 0 then t.Comment when c1.ColumnName = ''Time'' then t.Time else t.Value end as Value
                FROM [Transaction] t
                join Chemical c on t.Chem_Id = c.ChemicalId    
                join SamplePoint sp on t.SamplePoint_Id = sp.SampleId
                join Source s on sp.Source_Id = s.SourceId         
                join #Columns c1 
                ON c.Abbrev = c1.ColumnName 
                where s.Name = ''' + @SourceName + ''' and t.EntryDate = ''' + @Date + '''
            ) x
            pivot 
            (
                max(Value)
                for ColumnName in (' + @cols + ')
            ) p '

--print @cols
--print @query
execute sp_executesql @query;

这是我的结果:

Time    Area    Density Ref Index   H2SO4   pH  Urea    AN  TN  Ratio   NH3 SpGr    Cl2 Fe  Gross   Comment<br>
1220    NULL    2   3   4   5   693.51  -729.68 404.01  -0.64   0.1 2.018   8   7   9   8888888888888

问题是我只从查询中返回一条记录,而我想要的是两条记录 - 一条用于 Time = 1219,一条用于 Time = 1220。我知道(或认为)问题在于汇总函数 MAX,它使查询返回具有“最大值”的记录。我如何获得这两个记录?如果没有聚合函数,我无法让数据透视函数工作。谢谢。

【问题讨论】:

  • 从 PIVOT 列表中排除时间列,因为您希望旋转每个时间记录的所有值。
  • 谢谢亚历克斯!我创建并填充了变量 colsWithoutTime,它现在包含:[Area],[Density],[Ref Index],[H2SO4],[pH],[Urea],[AN],[TN],[Ratio],[NH3 ],[SpGr],[Cl2],[Fe],[Gross],[Comment] 我在 PIVOT 列表中使用 colsWithoutTime 而不是 @cols。我现在得到错误:列名“时间”无效。如果我使用 colsWithoutTime 在查询中构建 SELECT 列表,则结果在相同的值列表中,没有时间字段:面积密度参考指数 H2SO4 pH 尿素 AN TN 比率 NH3 SpGr Cl2 Fe Gross Comment NULL 2 3 4 5 693.51 - 729.68 404.01 -0.64 0.10 2.018 8 7 9 8888888888888
  • 您的子查询(具有内部连接的查询)不返回时间列,因此出现错误。我的建议: 1. 创建 SQL 查询的非动态版本(包括所有列)并首先使其工作,然后才将其转换为动态 SQL。 2. 再次仔细阅读[PIVOT][technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx) 文档,注意PIVOT查询的每个部分都返回了哪些列。
  • 感谢您的回复亚历克斯。你可能是对的,我错了,但我不认为我的内部查询应该返回 Time 列。它应该返回列 ColumnName 和 Value 并将这些值转换到另一个包含变量 @cols 中的列的表中。它不会产生错误;它返回数据透视表,但它只包含 MAX 此查询:
    SELECT c1.ColumnName, case when len(t.Comment) > 0 then t.Comment when c1.ColumnName = 'Time' then t.Time else t.Value end as Value
  • 返回 ColumnName 和 Value,但 Time 的值被 case 语句插入到 Value 列中。我将查询更改为具有硬编码的列名:

标签: sql pivot aggregate-functions sql-server-2014


【解决方案1】:

您仍未从 PIVOTed 列中排除时间。请注意,当我说从 PIVOT 中排除时,我不仅仅意味着您将它们从 PIVOT ... IN 列表中删除,而且您还更改了内部查询以将时间列作为 单独的 列返回。这就是为什么我建议仔细阅读 MSDN Pivot 文档以了解 PIVOT 函数的工作原理。

内部查询SELECT应该改成这个(Time作为单独的列返回,CASE没有提及):

SELECT t.TIME, c1.ColumnName,
    CASE 
        WHEN len(t.Comment) > 0     THEN t.Comment
        ELSE t.Value
    END AS Value

Pivot 部分应该变成这个(没有Time 列):

pivot ( max(Value) for ColumnName in ([Area], [Density], [Ref Index], [H2SO4], [pH], [Urea], [AN]], [TN], [Ratio], [NH3], [SpGr], [Cl2], [Fe], [Gross], [Comment]) ) p 

#Columns 表中删除时间。

【讨论】:

  • 哦,您说得对,先生。我确实阅读了您引用的文章,但我仍然错了。谢谢!
猜你喜欢
  • 2013-08-09
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多