[英]SQL Server Combine multiple rows to one row with multiple columns
I have a database in which I have the following rows: 我有一个数据库,其中包含以下行:
ID | Date start | Date end
----------------------------------
a | 01-01-1950 | 30-01-1951
a | 01-01-1948 | 31-12-1949
a | 31-01-1951 | 01-06-2000
b | 01-01-1980 | 01-08-2010
c | 01-01-1990 | 31-12-2017
c | 31-01-1985 | 31-12-1989
What I got 我得到了什么
Select query which I want to return the following: 选择要返回以下内容的查询:
ID | Date start 1 | Date end 1 | Date start 2 | Date end 2 | Date start 3 | Date end 3
---------------------------------------------------------------------------------------------------
a | 01-01-1948 | 31-12-1949 | 01-01-1950 | 30-01-1951 | 31-01-1951 | 01-06-2000
b | 01-01-1980 | 01-08-2010
c | 31-01-1985 | 31-12-1989 | 01-01-1990 | 31-12-2017
What I want: 我想要的是:
Most things I was able to find wanted it in the same column, or wouldn't want it sorted on chronological order, so unfortunately those situations didn't apply to me. 我能找到的大多数东西都希望在同一列中进行,或者不希望按时间顺序进行排序,因此不幸的是,这些情况不适用于我。
I really have now clue how to solve this. 我现在真的知道如何解决这个问题。
If you have only three dates, then pivot
/conditional aggregation should be fine: 如果只有三个日期,则
pivot
/条件聚合应该可以:
select id,
max(case when seqnum = 1 then dstart end) as start_1,
max(case when seqnum = 1 then dend end) as end_1,
max(case when seqnum = 2 then dstart end) as start_2,
max(case when seqnum = 2 then dend end) as end_2,
max(case when seqnum = 3 then dstart end) as start_3,
max(case when seqnum = 3 then dend end) as end_3
from (select t.*,
row_number() over (partition by id order by dstart) as seqnum
from t
) t
group by id;
Note: You have to specify the number of columns in the output. 注意:您必须指定输出中的列数。 If you don't know how many there are, you can either:
如果您不知道有多少个,可以:
Gordon's conditional aggregation would be my first choice. 戈登的条件聚合将是我的首选。 However, If you need to go DYNAMIC
但是,如果您需要动态
Declare @SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(concat('Date Start ',RN)) +',' + QuoteName(concat('Date End ',RN))
From (Select Distinct RN=Row_Number() over (Partition By ID Order By [Date Start])
From YourTable) A
Order by 1 For XML Path('')),1,1,'')
Select @SQL = '
Select [ID],' + @SQL + '
From (
Select ID,B.*
From (
Select *,RN=Row_Number() over (Partition By ID Order By [Date Start]) From YourTable
) A
Cross Apply (Values (concat(''Date Start '',A.RN),A.[Date Start])
,(concat(''Date End '',A.RN),A.[Date End]) ) B (Col,Value)
) A
Pivot (max(Value) For [Col] in (' + @SQL + ') ) p'
Exec(@SQL);
Returns 退货
Assuming you have a static number of date-ranges, you could achieve this using a window function as follows... 假设您有固定数量的日期范围,则可以使用如下窗口函数来实现此目的...
;WITH cteData
(
ID,
DateStart,
DateEnd
)
AS
(
SELECT 'a', CONVERT(DATE, '01-01-1950'), CONVERT(DATE, '30-01-1951')
UNION ALL SELECT 'a', '01-01-1948', '31-12-1949'
UNION ALL SELECT 'a', '31-01-1951', '01-06-2000'
UNION ALL SELECT 'b', '01-01-1980', '01-08-2010'
UNION ALL SELECT 'c', '01-01-1990', '31-12-2017'
UNION ALL SELECT 'c', '31-01-1985', '31-12-1989'
),
cteDefineColumns
AS
(
SELECT RangeColumnID = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DateStart),
*
FROM cteData
)
SELECT col1.ID,
[Date start 1] = col1.DateStart,
[Date end 1] = col1.DateEnd,
[Date start 2] = col2.DateStart,
[Date end 2] = col2.DateEnd,
[Date start 3] = col3.DateStart,
[Date end 3] = col3.DateEnd
FROM cteDefineColumns AS col1
LEFT OUTER JOIN cteDefineColumns AS col2
ON col1.ID = col2.ID
AND col2.RangeColumnID = 2
LEFT OUTER JOIN cteDefineColumns AS col3
ON col1.ID = col3.ID
AND col3.RangeColumnID = 3
WHERE col1.RangeColumnID = 1
ORDER BY col1.ID,
col1.DateStart,
col1.DateEnd;
I'm not sure why do you neet it, because this structure is not too good. 我不确定为什么要取消它,因为这种结构不太好。
if object_Id('tempdb..#TmpRankedTable') is not null drop table #TmpRankedTable
select Id, strt_dt, end_dt, row_number() over(partition by Id order by strt_dt) OrbyCol
into #TmpRankedTable
from dbo.YourTable
if object_Id('tempdb..#TmpStarts') is not null drop table #TmpStarts
select *
into #TmpStarts
from (
select Id, strt_dt, OrbyCol
from #TmpRankedTable) t
pivot (min(strt_dt) for OrbyCol in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])) p
if object_Id('tempdb..#TmpEnds') is not null drop table #TmpEnds
select *
into #TmpEnds
from (
select Id, end_dt, OrbyCol
from #TmpRankedTable) t
pivot (min(end_dt) for OrbyCol in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])) p
select
s.Id,
s.[1] [Start 1],
e.[1] [End 1],
s.[2] [Start 2],
e.[2] [End 2],
s.[3] [Start 3],
e.[3] [End 3],
s.[4] [Start 4],
e.[4] [End 4],
s.[5] [Start 5],
e.[5] [End 5],
s.[6] [Start 6],
e.[6] [End 6],
s.[7] [Start 7],
e.[7] [End 7],
s.[8] [Start 8],
e.[8] [End 8],
s.[9] [Start 9],
e.[9] [End 9],
s.[10] [Start 10],
e.[10] [End 10]
from #TmpStarts s
inner join #TmpEnds e on s.Id = e.Id
You can use pivot to transpose and query as below: 您可以按以下方式使用数据透视进行转置和查询:
;with cte as (
select *, RowN = row_number() over(partition by id order by datestart) from #temp )
, cte2 as (
select id, [1] as [datestart1], [2] as [datestart2], [3] as datestart3 from
(select id, datestart, RowN from cte) sourcetable
pivot (max(datestart) for RowN in ([1],[2],[3]) ) p
)
, cte3 as (
select id, [1] as [dateend1], [2] as [dateend2], [3] as dateend3 from
(select id, dateend, RowN from cte) sourcetable
pivot (max(dateend) for RowN in ([1],[2],[3]) ) p
) select c2.id, c2.datestart1,c3.dateend1,c2.datestart2,c3.dateend2,c2.datestart3,c3.dateend3
from cte2 c2 left join cte3 c3 on c2.id = c3.id
If you have dynamic columns you can create dynamic query using stuff to create list of columns and run this query as dynamic query to get all list of columns 如果您有动态列,则可以使用东西创建动态查询以创建列列表,并将此查询作为动态查询运行以获取所有列列表
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.