【发布时间】: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