我有两张表,关系是一对多。 执行查询后,我得到了结果表:
+-------+------------------+-----------+-------+--------+
| index | date | sub_index | angle | length |
+-------+------------------+-----------+-------+--------+
| 681 | 19/10/2016 15:49 | 1 | 30 | 333 |
| 681 | 19/10/2016 15:49 | 1 | 60 | 666 |
| 682 | 19/10/2016 15:52 | 2 | 0 | 44 |
| 682 | 19/10/2016 15:52 | 2 | 45 | 77 |
| 682 | 19/10/2016 15:52 | 2 | 90 | 67 |
+-------+------------------+-----------+-------+--------+
但是用户要求信息是平的。如下:
+-------+------------------+-----------+--------+---------+--------+---------+--------+---------+
| index | date | sub_index | angle1 | length1 | angle2 | length2 | angle3 | length3 |
+-------+------------------+-----------+--------+---------+--------+---------+--------+---------+
| 681 | 19/10/2016 15:49 | 1 | 30 | 333 | 60 | 666 | | |
| 682 | 19/10/2016 15:52 | 2 | 0 | 44 | 45 | 77 | 90 | 67 |
+-------+------------------+-----------+--------+---------+--------+---------+--------+---------+
角度和长度的数量是未知的,可以是任意数量的项目。
我读到了关于PIVOT
的内容,但我真的不知道如何在此示例中使用它,因为已更改的列(angle1
,angle2
...)和因为我读到PIVOT
需要一些函数(MAX
,COUNT
,...),我需要这个值......
答案 0 :(得分:1)
要做到这一点,你在初始查询中缺少一个属性。让我们称之为类型。然后,您可以使用下面的查询来执行您想要的操作。
drop table if exists dbo.TableC;
create table dbo.TableC (
_Index int
, Date datetime
, Sub_index int
, Angle int
, Length int
, Type int
);
insert into dbo.TableC (_Index, Date, Sub_index, Angle, Length, Type)
values (681, CONVERT(datetime, '19/10/2016 15:49', 103), 1, 30, 333, 1)
, (681, CONVERT(datetime, '19/10/2016 15:49', 103), 1, 60, 666, 2)
, (682, CONVERT(datetime, '19/10/2016 15:52', 103), 2, 0, 44, 1)
, (682, CONVERT(datetime, '19/10/2016 15:52', 103), 2, 45, 77, 2)
, (682, CONVERT(datetime, '19/10/2016 15:52', 103), 2, 90, 67, 3)
select
t._Index, t.Date, t.Sub_index
, max(case when t.Type = 1 then t.Angle else null end) as Angle1
, max(case when t.Type = 1 then t.Length else null end) as Length1
, max(case when t.Type = 2 then t.Angle else null end) as Angle2
, max(case when t.Type = 2 then t.Length else null end) as Length2
, max(case when t.Type = 3 then t.Angle else null end) as Angle3
, max(case when t.Type = 3 then t.Length else null end) as Length3
from dbo.TableC t
group by t._Index, t.Date, t.Sub_index
答案 1 :(得分:1)
这是一种可能的动态解决方案。请注意,结果表中的列数取决于输入数据,这通常是个坏主意。因此,将此代码放在存储过程中会很棘手。
尽管如此,这是一个TSQL片段,应该回答你的问题:
--create a custom type that will be used in the final dynamic call
if exists (select * from sys.types where name = 'TestTableType')
drop type TestTableType
create type TestTableType as table([index] int,[sub_index] int, [data] nvarchar(max))
go
--this table contains your input data
declare @tem table([index] int, [date] datetime , [sub_index] int, [angle] decimal (19,6),[length] decimal (19,6))
--temp table used to calculate maximum number of columns to show
declare @counters table([index] int,[sub_index] int, [counter] int)
--temp table that will hold denormalized values (one row for each index/subindex couple)
declare @denormalized_data TestTableType
--this variables contains the maximum number of columns to show
declare @max_columns int
--this variable will contain the dunamically generated TSQL query that will give the final result
declare @dynamic_query nvarchar(max)
--support variables used to generate dynamic query
declare @counter int
declare @counter_str nvarchar(max)
--1. populate input data
insert into @tem select 681 , '20161019 15:49', 1 , 30, 333
insert into @tem select 681 , '20161019 15:49', 1 , 60, 666
insert into @tem select 682 , '20161019 15:52', 2 , 0, 44
insert into @tem select 682 , '20161019 15:52', 2 , 45, 77
insert into @tem select 682 , '20161019 15:52', 2 , 90, 67
--insert into @tem select 682 , '20161019 15:52', 2 , 8, 88
--2. calculate the number of columns to show
insert into @counters
select [index],[sub_index], COUNT(*) from @tem group by [index],[sub_index]
select @max_columns = max([counter]) from @counters
--3. denormalize data using an XML-based approach to obtain one row for each index/subindex couple
insert into @denormalized_data
SELECT
[index],[sub_index],
'<MyData>'+ STUFF((
SELECT ' <angle>' + CAST([angle] AS VARCHAR(MAX)) + '</angle><length>' + CAST([length] AS VARCHAR(MAX)) +'</length>'
FROM @tem
WHERE ([index] = Results.[index] and [sub_index] = Results.[sub_index])
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') + '</MyData>' AS NameValues
FROM @tem Results
GROUP BY [index],[sub_index]
--4. generate a dynamic TSQL query with the correct number of columns
set @counter = 0
set @dynamic_query=' SELECT [index],[sub_index], '
while @counter < @max_columns
begin
set @counter = @counter +1
set @counter_str = CAST(@counter as nvarchar(max))
set @dynamic_query = @dynamic_query + ' CONVERT(XML,[data]).value(''/MyData[1]/angle['+ @counter_str + ']'',''varchar(100)'') AS angle'+ @counter_str + ', '
set @dynamic_query = @dynamic_query + ' CONVERT(XML,[data]).value(''/MyData[1]/length['+ @counter_str + ']'',''varchar(100)'') AS length'+ @counter_str + ', '
end
set @dynamic_query = substring(@dynamic_query,1,LEN(@dynamic_query) - 1) + ' FROM @denormalized_d '
exec sp_executesql @dynamic_query, N'@denormalized_d TestTableType readonly', @denormalized_data
以下是具有3个不同值的输出:
以下是具有4个不同值的输出(只需取消注释行--insert into @tem select 682 , '20161019 15:52', 2 , 8, 88
):