Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Запрос на конкатенацию интервалов  [new]
remi_
Member

Откуда: СПб
Сообщений: 248
Есть три таблицы, содержащие временные интервалы.

declare @A table (AId int, BeginDate smalldatetime, EndDate smalldatetime, PRIMARY KEY (AId, BeginDate))
declare @B table (AId int, BId int, CId int, BeginDate smalldatetime, EndDate smalldatetime, BValue int, PRIMARY KEY (AId, BId, CId, BeginDate))
declare @C table (CId int, BeginDate smalldatetime, EndDate smalldatetime, CValue int, PRIMARY KEY (CId, BeginDate))

insert into @A (AId, BeginDate, EndDate) select
1, '19000101', '20500101' union all select
2, '20120101', '20121231'

insert into @B (AId, BId, CId, BeginDate, EndDate, BValue) select
1, 100, 1000, '19000101','20120102', 21 union all select
1, 100, 1000, '20120105','20120201', 22 union all select
1, 100, 1000, '20120202','20120220', 23 union all select
1, 200, 1001, '20120101','20120401', 24 union all select
2, 100, 1000, '20120101','20120601', 25 

insert into @C (CId, BeginDate, EndDate, CValue) select
1000, '20110101','20120107', 250 union all select
1000, '20120108','20120210', 251 union all select
1000, '20120211','20500101', 252 union all select
1001, '20110101','20120104', 253 union all select
1001, '20120105','20500101', 254 


По каждой таблице гарантированно, что BeginDate <= EndDate и интервалы не пересекаются в рамках PRIMARY KEY. Все даты с точностью до дня (без минут, секунд).
Необходимо сформировать результирующую систему интервалов, на которых существует одновременно информация по всем таблицам, т.е. ожидается


AId BId CId BeginDate EndDate BValue CValue

1 100 1000 '20110101' '20120102' 21 250
1 100 1000 '20120105' '20120201' 22 251
1 100 1000 '20120202' '20120210' 23 251
1 100 1000 '20120211' '20120220' 23 252
1 200 1001 '20120101' '20120104' 24 253
1 200 1001 '20120105' '20120401' 24 254
2 100 1000 '20120101' '20120107' 25 250
2 100 1000 '20120108' '20120210' 25 251
2 100 1000 '20120211' '20120601' 25 252

P.S.
1. Кроссировка по дням не подойдет по времени выполнения, данных довольно много и период в годах достаточно большой.
2. Собирать все BeginDate, EndDate по трем таблицам по distinct и, на основе этой информации, строить интервалы не самый лучший путь – задача существенно шире описанной, не хочу морочить вам голову, просто примите, как данность.
3 сен 12, 13:00    [13104851]     Ответить | Цитировать Сообщить модератору
 Re: Запрос на конкатенацию интервалов  [new]
Anddros
Member

Откуда:
Сообщений: 1077
select b.AId, b.BId, b.CId, d1.BeginDate, d2.EndDate, b.BValue, c.CValue
from @B b
inner join @A a on a.AId = b.AId
inner join @C c on c.CId = b.CId
cross apply (select max(BeginDate)BeginDate from (select a.BeginDate union all select b.BeginDate union all select c.BeginDate)t )d1
cross apply (select min(EndDate)EndDate from (select a.EndDate union all select b.EndDate union all select c.EndDate)t )d2
where (a.BeginDate < b.EndDate and b.BeginDate < a.EndDate) 
	and (a.BeginDate < c.EndDate and c.BeginDate < a.EndDate) 
	and (b.BeginDate < c.EndDate and c.BeginDate < b.EndDate) 
3 сен 12, 13:46    [13105356]     Ответить | Цитировать Сообщить модератору
 Re: Запрос на конкатенацию интервалов  [new]
aleks2
Guest
Anddros
select b.AId, b.BId, b.CId, d1.BeginDate, d2.EndDate, b.BValue, c.CValue
from @B b
inner join @A a on a.AId = b.AId
inner join @C c on c.CId = b.CId
cross apply (select max(BeginDate)BeginDate from (select a.BeginDate union all select b.BeginDate union all select c.BeginDate)t )d1
cross apply (select min(EndDate)EndDate from (select a.EndDate union all select b.EndDate union all select c.EndDate)t )d2
where (a.BeginDate < b.EndDate and b.BeginDate < a.EndDate) 
	and (a.BeginDate < c.EndDate and c.BeginDate < a.EndDate) 
	and (b.BeginDate < c.EndDate and c.BeginDate < b.EndDate) 

Cross apply для понта, чтоль?
3 сен 12, 14:10    [13105572]     Ответить | Цитировать Сообщить модератору
 Re: Запрос на конкатенацию интервалов  [new]
Anddros
Member

Откуда:
Сообщений: 1077
aleks2
Cross apply для понта, чтоль?
Разруливай поиск максимальной/минимльной через case'ы, если желаешь. Для трех дат это еще сравнимо по объему кода, если больше - упаришься писать и проще допустить ошибку при копипасте. По времени же выполнения разницы скорей всего не будет.

И с cross apply, в которые засунуты промежуточные вычисления, сложные запросы намного проще читаются. Ну это уж сугубое ИМХО. :)
3 сен 12, 14:39    [13105969]     Ответить | Цитировать Сообщить модератору
 Re: Запрос на конкатенацию интервалов  [new]
remi_
Member

Откуда: СПб
Сообщений: 248
Во первых, сердечное мерси.

Во вторых
Anddros
Разруливай поиск максимальной/минимльной через case'ы, если желаешь.


скорее всего имелось в виду, а почему не

select b.AId, b.BId, b.CId, 
	(select max(BeginDate)BeginDate from (select a.BeginDate union all select b.BeginDate union all select c.BeginDate)t ) as BeginDate, 
	(select min(EndDate)EndDate from (select a.EndDate union all select b.EndDate union all select c.EndDate)t ) as EndDate,
	b.BValue, c.CValue
from @B b
inner join @A a on a.AId = b.AId
inner join @C c on c.CId = b.CId
where (a.BeginDate < b.EndDate and b.BeginDate < a.EndDate) 
	and (a.BeginDate < c.EndDate and c.BeginDate < a.EndDate) 
	and (b.BeginDate < c.EndDate and c.BeginDate < b.EndDate) 


Собственно, синонимично и кому как проще читать.
3 сен 12, 15:23    [13106374]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить