SQL:如何按特定列的值“拆分”表中的行?
我有一个表,其中的行如下:SQL:如何按特定列的值“拆分”表中的行?,sql,sql-server,database,tsql,select,Sql,Sql Server,Database,Tsql,Select,我有一个表,其中的行如下: Name | date_from | date_to | age ------+------------+------------+----- Alice | 01.12.2004 | 03.04.2008 | 35 Bob | 04.02.2013 | 04.11.2014 | 43 Name | date_from | date_to | age ------+------------+------------+----- Alice |
Name | date_from | date_to | age
------+------------+------------+-----
Alice | 01.12.2004 | 03.04.2008 | 35
Bob | 04.02.2013 | 04.11.2014 | 43
Name | date_from | date_to | age
------+------------+------------+-----
Alice | 01.12.2004 | 01.12.2005 | 35
Alice | 01.12.2005 | 01.12.2006 | 36
Alice | 01.12.2006 | 01.12.2007 | 37
Alice | 01.12.2007 | 01.12.2008 | 38
Alice | 01.12.2008 | 03.04.2008 | 39
Bob | 04.02.2013 | 04.02.2014 | 43
Bob | 04.02.2014 | 04.11.2014 | 44
我想制作一个表格,将每行按
date_from和date_to列,保留名称并更新年龄,如下所示:
Name | date_from | date_to | age
------+------------+------------+-----
Alice | 01.12.2004 | 03.04.2008 | 35
Bob | 04.02.2013 | 04.11.2014 | 43
Name | date_from | date_to | age
------+------------+------------+-----
Alice | 01.12.2004 | 01.12.2005 | 35
Alice | 01.12.2005 | 01.12.2006 | 36
Alice | 01.12.2006 | 01.12.2007 | 37
Alice | 01.12.2007 | 01.12.2008 | 38
Alice | 01.12.2008 | 03.04.2008 | 39
Bob | 04.02.2013 | 04.02.2014 | 43
Bob | 04.02.2014 | 04.11.2014 | 44
在SQL中可以做到这一点吗?一种解决方案是生成一个数字列表,并将其与原始表连接,在开始日期加上年份,直到到达结束日期为止 下面的查询处理长达5年的时间跨度要支持更多年,您需要使用更多值扩展子查询 这是你的问题
;with cte as (
select 1 as ctr, DATEDIFF(year, cast(date_from as datetime), cast(date_to as datetime)) as ct
,cast(date_from as date) as dt, cast(date_from as date) as dt2, date_to, cast(age as int) as age, [name] from test
union all
select ctr + 1, ct, dateadd(year, 1, dt), dt2, date_to, age + 1, [name] from cte
where ctr + 1 <= ct+1)
select [name], dt as date_from, case when ctr - 1 != ct then dt else date_to end as date_to, age from cte order by dt2, age
输出:
使用SQL Server的另一种可能的解决方案
-- data preparation
create table test1
(
name varchar(20),
date_from date,
date_to date ,
age int
)
insert into test values ('alice' , '01-2-2008' , '11-3-2014' , 35 )
insert into test values ('bob' , '06-2-2005' , '7-10-2016' , 20)
create table test2
(
name varchar(20),
date_from date,
date_to date ,
age int
)
-- query
declare @name varchar(20)
declare @date_from date
declare @date_to date
declare @age int
declare @date_step as date
declare @sql_st as nvarchar(max)
declare cur cursor for select name, date_from , date_to , age from test
open cur;
fetch next from cur into @name , @date_from , @date_to , @age
while @@FETCH_STATUS = 0
begin
set @date_step = dateadd(year,1,@date_from)
while @date_to > @date_step
begin
set @sql_st = concat('insert into test2 values (''',@name , ''' , ''' , @date_from , ''' , ''',@date_step,''',',@age , ' )')
print(@sql_st)
exec sp_executesql @sql_st
set @date_from = @date_step
set @date_step = dateadd(year,1,@date_step)
set @age = @age + 1
end
set @sql_st = concat('insert into test2 values (''',@name , ''' , ''' , @date_from , ''' , ''',@date_to,''',',@age , ' )')
exec sp_executesql @sql_st
--print(@sql_st)
fetch next from cur into @name , @date_from , @date_to , @age
end
close cur;
deallocate cur;
您使用的是什么sql?MS sql、MySQL、Oracle、PostgreSQL?有一个帮助表或递归cte,可以返回所有可能的年份。JOIN.好像少了一个Alice | 01.12.2008 | 03.04.2008 | 38 Bob也一样,或者Bob第二排不应该是there@metal:您完全正确,will Correct方言不可知的答案可能很难回答,因为日期函数是高度特定于供应商的。最好使用现有的理货表,或者您可以使用…内部联接值1,2,3,4,5,6,7 xn。。。而不是union all查询。还有一个投票站在我这边。@ZoharPeled:是的,这里的值语法要短得多,我相应地更新了我的答案。谢谢