2012-04-06 3 views
5

Давать следующие 2 таблицы:Как объединить диапазоны из различных таблиц

T1 
------------------ 
From | To | Value 
------------------ 
10 | 20 | XXX 
20 | 30 | YYY 
30 | 40 | ZZZ 


T2 
------------------ 
From | To | Value 
------------------ 
10 | 15 | AAA 
15 | 19 | BBB 
19 | 39 | CCC 
39 | 40 | DDD 

Что является лучшим способом, чтобы получить результат ниже, с помощью T-SQL на SQL Server 2008?

От/К диапазонов являются последовательными (нет зазоров), а следующий Из всегда имеет то же значение, что и предыдущий To

Desired result 
------------------------------- 
From | To | Value1 | Value2 
------------------------------- 
10 | 15 | XXX | AAA 
15 | 19 | XXX | BBB 
19 | 20 | XXX | CCC 
20 | 30 | YYY | CCC 
30 | 39 | ZZZ | CCC 
39 | 40 | ZZZ | DDD 

ответ

4

Сначала я объявляю данные, которые выглядят как данные, которые вы опубликовали. Пожалуйста, исправьте меня, если какие-либо допущения, которые я сделал, ошибочны. Лучше было бы разместить свое собственное объявление в вопросе, чтобы мы все работали с одними и теми же данными.

DECLARE @T1 TABLE (
    [From] INT, 
    [To] INT, 
    [Value] CHAR(3) 
); 

INSERT INTO @T1 (
    [From], 
    [To], 
    [Value] 
) 
VALUES 
    (10, 20, 'XXX'), 
    (20, 30, 'YYY'), 
    (30, 40, 'ZZZ'); 

DECLARE @T2 TABLE (
    [From] INT, 
    [To] INT, 
    [Value] CHAR(3) 
); 

INSERT INTO @T2 (
    [From], 
    [To], 
    [Value] 
) 
VALUES 
    (10, 15, 'AAA'), 
    (15, 19, 'BBB'), 
    (19, 39, 'CCC'), 
    (39, 40, 'DDD'); 

Вот мой запрос на выборку, чтобы сгенерировать ожидаемый результат:

SELECT 
    CASE 
    WHEN [@T1].[From] > [@T2].[From] 
    THEN [@T1].[From] 
    ELSE [@T2].[From] 
    END AS [From], 
    CASE 
    WHEN [@T1].[To] < [@T2].[To] 
    THEN [@T1].[To] 
    ELSE [@T2].[To] 
    END AS [To], 
    [@T1].[Value], 
    [@T2].[Value] 
FROM @T1 
INNER JOIN @T2 ON 
    (
    [@T1].[From] <= [@T2].[From] AND 
    [@T1].[To] > [@T2].[From] 
) OR 
    (
    [@T2].[From] <= [@T1].[From] AND 
    [@T2].[To] > [@T1].[From] 
); 
+0

Результат строки 5 был неправильным. Теперь исправлено. Благодарю. – pvieira

+0

Я удалил свой комментарий о том, что результирующие наборы отличаются друг от друга, теперь, когда они совпадают. –

0

В приведенной ниже запрос находит самые маленькие диапазоны, то снова возвращает таблицы обратно:

SELECT ranges.from, ranges.to, T1.Value, T2.Value 
FROM (SELECT all_from.from, min(all_to.to) as to 
    FROM (SELECT T1.FROM 
     FROM T1 
     UNION 
     SELECT T2.FROM 
     FROM T2) all_from 
    JOIN (SELECT T1.TO 
     FROM T1 
     UNION 
     SELECT T2.FROM 
     FROM T2) all_to ON all_from.from < all_to.to 
    GROUP BY all_from.from) ranges 
JOIN T1 ON ranges.from >= T1.from AND ranges.to <= T1.to 
JOIN T2 ON ranges.from >= T2.from AND ranges.to <= T2.to 
ORDER BY ranges.from 
+1

Я не могу скомпилировать этот запрос. Как вы установили свои тестовые данные? –

+0

Не хватало GROUP BY, попробуйте еще раз, теперь он работает. – GavinCattell

+0

Это все еще не компилируется для меня, используя мою настройку данных. В копии вашего запроса я заменил все вхождения 'T1' на' [@ T1] 'и все вхождения' T2' с '[@ T2]' и получил эту синтаксическую ошибку при выполнении: 'Msg 156, Level 15 , State 1, Line 34 Неверный синтаксис рядом с ключевым словом 'from'.' –

0

Спасибо за ответы, но я закончил с использованием CTE, wgich я думаю чище.

DECLARE @T1 TABLE ([From] INT, [To] INT, [Value] CHAR(3)); 
DECLARE @T2 TABLE ([From] INT, [To] INT, [Value] CHAR(3)); 

INSERT INTO @T1 ( [From], [To], [Value]) VALUES (10, 20, 'XXX'), (20, 30, 'YYY'), (30, 40, 'ZZZ'); 
INSERT INTO @T2 ( [From], [To], [Value]) VALUES (10, 15, 'AAA'), (15, 19, 'BBB'), (19, 39, 'CCC'), (39, 40, 'DDD'); 

;with merged1 as 
(
    select 
     t1.[From] as from1, 
     t1.[to] as to1, 
     t1.Value as Value1, 
     t2.[From] as from2, 
     t2.[to] as to2, 
     t2.Value as Value2 
    from @t1 t1 
    inner join @T2 t2 
     on t1.[From] < t2.[To] 
     and t1.[To] >= t2.[From] 

) 
,merged2 as 
(
    select 
      case when from2>=from1 then from2 else from1 end as [From] 
     ,case when to2<=to1 then to2 else to1 end as [To] 
     ,value1 
     ,value2 
    from merged1 
) 
select * from merged2 
3

Кража установки данных @ Isme, я написал следующее:

;With EPs as (
    select [From] as EP from @T1 
    union 
    select [To] from @T1 
    union 
    select [From] from @T2 
    union 
    select [To] from @T2 
), OrderedEndpoints as (
    select EP,ROW_NUMBER() OVER (ORDER BY EP) as rn from EPs 
) 
select 
    oe1.EP, 
    oe2.EP, 
    t1.Value, 
    t2.Value 
from 
    OrderedEndpoints oe1 
     inner join 
    OrderedEndpoints oe2 
     on 
      oe1.rn = oe2.rn - 1 
     inner join 
    @T1 t1 
     on 
      oe1.EP < t1.[To] and 
      oe2.EP > t1.[From] 
     inner join 
    @T2 t2 
     on 
      oe1.EP < t2.[To] and 
      oe2.EP > t2.[From] 

То есть, вы создаете набор, содержащий все возможные конечные точки периодов (EPs), то вы «сортировать» те и назначить каждому номер строки (OrderedEPs).

Затем окончательный запрос собирает каждую «соседнюю» пару строк и присоединяется к исходным таблицам, чтобы найти, какие строки из каждого перекрывают выбранный диапазон.

Смежные вопросы