如何使数据行成为分组列?

时间:2015-09-21 14:51:40

标签: sql-server

我想按ID进行分组,但每个列组都显示为一组新的水平列。

我有一个包含这样数据的表

╔════╦═══════╦════════╗
║ ID ║ Phone ║  Type  ║
╠════╬═══════╬════════╣
║  A ║   111 ║ home   ║
║  A ║   222 ║ work   ║
║  B ║   333 ║ cell   ║
║  B ║   444 ║ school ║
╚════╩═══════╩════════╝

我希望它看起来像

╔════╦════════╦═══════╦════════╦════════╗
║ ID ║ Phone1 ║ Type1 ║ Phone2 ║ Type2  ║
╠════╬════════╬═══════╬════════╬════════╣
║  A ║    111 ║ home  ║    222 ║ work   ║
║  B ║    333 ║ cell  ║    444 ║ school ║
╚════╩════════╩═══════╩════════╩════════╝

理想情况下,我会找到一个可以处理任意数量的重复组的解决方案,但如果必须的话我可以硬编码。

我最多可以拥有100,000个唯一ID,其中包含20个重复的列组,每组最多包含5个列。

似乎PIVOT会对此有所帮助,但我无法弄清楚如何。

编辑:在这里要非常清楚我不希望行数据成为列标题。我希望重复当前列标题并使行数据跨越到水平组。这里没有总结或汇总。这就是为什么PIVOT似乎不起作用(除非我错过了一些我希望是的东西!)

SQL Server 2012

1 个答案:

答案 0 :(得分:1)

以下是使用动态交叉表的示例,如Jeff Moden在sql server central上的文章所建议的那样。

他的文章可以在这里找到。 http://www.sqlservercentral.com/articles/Crosstab/65048/

if OBJECT_ID('tempdb..#Something') is not null
    drop table #Something

create table #Something
(
    ID char(1)
    , Phone int
    , MyType varchar(10)
)

insert #Something
select 'A', 111, 'home' union all
select 'A', 222, 'work' union all
select 'B', 333, 'cell' union all
select 'B', 444, 'school'

select *
from #Something

declare @StaticPortion nvarchar(2000) = 
'with OrderedResults as
(
    select *
        , ROW_NUMBER() over (partition by ID order by phone) as RowNum
    from #Something
)
select ID';

declare @DynamicPortion nvarchar(max) = '';
declare @FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by ID order by ID';


with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS 
(
    SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)

select @DynamicPortion = @DynamicPortion + 
    ', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Phone end) as Phone' + CAST(N as varchar(6)) +
    ', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then MyType end) as Type' + CAST(N as varchar(6))

from cteTally t
where t.N <= 
(
    select top 1 Count(*)
    from #Something
    group by ID
    order by COUNT(*) desc
)

select @StaticPortion + @DynamicPortion + @FinalStaticPortion

declare @SqlToExecute nvarchar(max) = @StaticPortion + @DynamicPortion + @FinalStaticPortion;
exec sp_executesql @SqlToExecute
相关问题