我在使用SQL时遇到问题。我有下表:
declare @t table (START_DATE datetime, END_DATE datetime, GROSS_SALES_PRICE decimal(10,2) ); insert into @t values ('2014-08-06 00:00:00.000', '2014-10-06 23:59:59.000', 29.99), ('2014-09-06 00:00:00.000', '2014-09-09 23:59:59.000', 32.99), ('2014-09-10 00:00:00.000', '2014-09-30 23:59:59.000', 32.99), ('2014-10-07 00:00:00.000', '2049-12-31 23:59:59.000', 34.99)
我想分开重叠的日期。例如,我在第一行START_DATE 2014-08-06和END_DATE 2014-10-06中。我们可以看到第二排和第三排的日期在第一排的这段时间之内。
所以我想将它们分开如下:
declare @t2 table (START_DATE datetime, END_DATE datetime, GROSS_SALES_PRICE decimal(10,2) ); insert into @t2 values ('2014-08-06 00:00:00.000', '2014-09-05 23:59:59.000', 29.99), ('2014-09-06 00:00:00.000', '2014-09-09 23:59:59.000', 32.99), ('2014-09-10 00:00:00.000', '2014-09-30 23:59:59.000', 32.99), ('2014-10-01 00:00:00.000', '2014-10-06 23:59:59.000', 29.99), ('2014-10-07 00:00:00.000', '2049-12-31 23:59:59.000', 34.99)
因此,第二和第三行保持不变。第一行应有新的END_DATE。我们也有新的一行。GROSS_SALES_PRICE应该保持内部期间的状态。感谢帮助。我正在使用SQL Server 2014
日历/日期表可以简化此操作,但是我们也可以使用查询使用公共表表达式生成临时日期表。
从那里,我们可以解决这是一个空白和孤岛式的问题。使用日期表并使用outer apply()获取最新值start_date,gross_sales_price我们可以使用两个 row_number() s来确定要重新聚合的组。第一个是由排序的date,减去另一个是按我们拥有的最新值进行划分并由start_date排序的date。
outer apply()
start_date
gross_sales_price
row_number()
date
然后,您可以将公用表表达式的结果转储src到临时表中,并使用该表进行插入/删除,也可以使用mergeusing src。
src
merge
/* -- dates --*/ declare @fromdate datetime, @thrudate datetime; select @fromdate = min(start_date), @thrudate = max(end_date) from #t; ;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n)) , dates as ( select top (datediff(day, @fromdate, @thrudate)+1) [Date]=convert(datetime,dateadd(day,row_number() over(order by (select 1))-1,@fromdate)) , [End_Date]=convert(datetime,dateadd(millisecond,-3,dateadd(day,row_number() over(order by (select 1)),@fromdate))) from n as deka cross join n as hecto cross join n as kilo cross join n as tenK cross join n as hundredK order by [Date] ) /* -- islands -- */ , cte as ( select start_date = d.date , end_date = d.end_date , x.gross_sales_price , grp = row_number() over (order by d.date) - row_number() over (partition by x.start_date order by d.date) from dates d outer apply ( select top 1 l.start_date, l.gross_sales_price from #t l where d.date >= l.start_date and d.date <= l.end_date order by l.start_date desc ) x ) /* -- aggregated islands -- */ , src as ( select start_date = min(start_date) , end_date = max(end_date) , gross_sales_price from cte group by gross_sales_price, grp ) /* -- merge -- */ merge #t with (holdlock) as target using src as source on target.start_date = source.start_date and target.end_date = source.end_date and target.gross_sales_price = source.gross_sales_price when not matched by target then insert (start_date, end_date, gross_sales_price) values (start_date, end_date, gross_sales_price) when not matched by source then delete output $action, inserted.*, deleted.*; /* -- results -- */ select start_date , end_date , gross_sales_price from #t order by start_date
extrester演示:http://rextester.com/MFXCQQ90933
merge 输出(您无需输出此内容,仅在演示中显示):
+---------+---------------------+---------------------+-------------------+---------------------+---------------------+-------------------+ | $action | START_DATE | END_DATE | GROSS_SALES_PRICE | START_DATE | END_DATE | GROSS_SALES_PRICE | +---------+---------------------+---------------------+-------------------+---------------------+---------------------+-------------------+ | INSERT | 2014-10-01 00:00:00 | 2014-10-06 23:59:59 | 29.99 | NULL | NULL | NULL | | INSERT | 2014-08-06 00:00:00 | 2014-09-05 23:59:59 | 29.99 | NULL | NULL | NULL | | DELETE | NULL | NULL | NULL | 2014-08-06 00:00:00 | 2014-10-06 23:59:59 | 29.99 | +---------+---------------------+---------------------+-------------------+---------------------+---------------------+-------------------+
结果:
+-------------------------+-------------------------+-------------------+ | start_date | end_date | gross_sales_price | +-------------------------+-------------------------+-------------------+ | 2014-08-06 00:00:00.000 | 2014-09-05 23:59:59.997 | 29.99 | | 2014-09-06 00:00:00.000 | 2014-09-09 23:59:59.997 | 32.99 | | 2014-09-10 00:00:00.000 | 2014-09-30 23:59:59.997 | 32.99 | | 2014-10-01 00:00:00.000 | 2014-10-06 23:59:59.997 | 29.99 | | 2014-10-07 00:00:00.000 | 2049-12-31 23:59:59.997 | 34.99 | +-------------------------+-------------------------+-------------------+