我有两张桌子:
a (column1, column2, column3)
b (column6, column7, column8)
a.column1
是b.column6
中的外键。
table a
中的一行有时匹配table b
中的3行,有时是5行,有时是1行....没有确定的返回行数。
我有业务要求将表b中的所有相应列翻转成一行..像这样:
a.column1, a.column2, a.column3, b.column7, b.column8, b.column7, b.column8
a.column1, a.column2, a.column3, b.column7, b.column8
a.column1, a.column2, a.column3, b.column7, b.column8, b.column7, b.column8, b.column7, b.column8
a.column1, a.column2, a.column3, b.column7, b.column8, b.column7, b.column8, b.column7, b.column8b.column7, b.column8, b.column7, b.column8
你看,表a中每行的列数总是3 ...但是从表b开始,你可能有一个可变数量的列......而且第7列和第8列必须按顺序重复出现。
我该怎么做?感谢。
答案 0 :(得分:1)
听起来您需要取消隐藏然后转动数据。如果你有一个未知数量的值,你将不得不使用动态SQL,但我首先建议先编写一个硬代码或静态版本的查询,然后将其转换为动态SQL。
取消数据取消的过程将在tableB
中占用您的多个列,并将其转换为多行。由于您使用的是SQL Server 2012,因此可以使用CROSS APPLY来取消数据的删除:
select column1, column2, column3,
col = col + '_' + cast(seq as varchar(10)),
value
from
(
select a.column1, a.column2, a.column3,
b.column6, b.column7, b.column8,
row_number() over(partition by a.column1
order by a.column1) seq
from tablea a
inner join tableb b
on a.column1 = b.column6
) d
cross apply
(
select 'column6', column6 union all
select 'column7', column7 union all
select 'column8', column8
) c (col, value);
见SQL Fiddle with Demo。这将给你一个类似于:
的结果| COLUMN1 | COLUMN2 | COLUMN3 | COL | VALUE |
| 1 | 2 | 3 | column6_1 | 1 |
| 1 | 2 | 3 | column7_1 | 18 |
| 1 | 2 | 3 | column8_1 | 56 |
| 1 | 2 | 3 | column6_2 | 1 |
| 1 | 2 | 3 | column7_2 | 25 |
| 1 | 2 | 3 | column8_2 | 89 |
正如您所看到的,您现在有多行可以轻松应用枢轴功能。 PIVOT代码将是:
select column1, column2, column3,
column6_1, column7_1, column8_1,
column6_2, column7_2, column8_2,
column6_3, column7_3, column8_3
from
(
select column1, column2, column3,
col = col + '_' + cast(seq as varchar(10)),
value
from
(
select a.column1, a.column2, a.column3,
b.column6, b.column7, b.column8,
row_number() over(partition by a.column1
order by a.column1) seq
from tablea a
inner join tableb b
on a.column1 = b.column6
) d
cross apply
(
select 'column6', column6 union all
select 'column7', column7 union all
select 'column8', column8
) c (col, value)
) src
pivot
(
max(value)
for col in (column6_1, column7_1, column8_1,
column6_2, column7_2, column8_2,
column6_3, column7_3, column8_3)
) piv;
见SQL Fiddle with Demo。由于您声明tableB
中可能包含未知或动态数量的条目,因此您需要使用动态SQL。这将生成一个sql字符串,将执行该字符串以获得最终结果:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(col +'_'+cast(seq as varchar(10)))
from
(
select row_number() over(partition by column6
order by column6) seq
from tableB
) t
cross apply
(
select 'column6', 1 union all
select 'column7', 2 union all
select 'column8', 3
) c (col, so)
group by col, so, seq
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT column1, column2, column3,' + @cols + '
from
(
select column1, column2, column3,
col = col + ''_'' + cast(seq as varchar(10)),
value
from
(
select a.column1, a.column2, a.column3,
b.column6, b.column7, b.column8,
row_number() over(partition by a.column1
order by a.column1) seq
from tablea a
inner join tableb b
on a.column1 = b.column6
) d
cross apply
(
select ''column6'', column6 union all
select ''column7'', column7 union all
select ''column8'', column8
) c (col, value)
) x
pivot
(
max(value)
for col in (' + @cols + ')
) p '
execute sp_executesql @query;
见SQL Fiddle with Demo。两个版本都给出了结果:
| COLUMN1 | COLUMN2 | COLUMN3 | COLUMN6_1 | COLUMN7_1 | COLUMN8_1 | COLUMN6_2 | COLUMN7_2 | COLUMN8_2 | COLUMN6_3 | COLUMN7_3 | COLUMN8_3 |
| 1 | 2 | 3 | 1 | 18 | 56 | 1 | 25 | 89 | (null) | (null) | (null) |
| 2 | 4 | 6 | 2 | 78 | 245 | (null) | (null) | (null) | (null) | (null) | (null) |
| 3 | 8 | 9 | 3 | 10 | 15 | 3 | 45 | 457 | 3 | 89 | 50 |