2012-04-06 13 views
5

Realizar las siguientes tablas: 2Cómo combinar rangos de diferentes tablas

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 

¿Cuál es la mejor manera de conseguir el resultado a continuación, utilizando T-SQL en SQL Server 2008?

El De/A rangos son secuenciales (no hay huecos) y el siguiente De siempre tiene el mismo valor que el anterior Para

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 

Respuesta

4

Primero declaro los datos que se parecen a los datos que ha publicado. Por favor corrígeme si alguna suposición que hice es incorrecta. Mejor sería publicar su propia declaración en la pregunta para que todos trabajemos con la misma información.

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'); 

Aquí es mi consulta de selección para generar el resultado esperado:

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

La fila de resultados 5 estaba equivocada. Está arreglado ahora. Gracias. – pvieira

+0

Quité mi comentario acerca de que los conjuntos de resultados son diferentes, ahora que son los mismos. –

0

La consulta siguiente busca los rangos más pequeños, a continuación, recupera los valores de nuevo en las tablas:

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

No puedo hacer esta compilación de consultas. ¿Cómo configuró sus datos de prueba? –

+0

Faltaba un GROUP BY, intenta de nuevo, funciona ahora. – GavinCattell

+0

Esto todavía no compila para mí usando mi configuración de datos. En una copia de su consulta reemplacé todas las ocurrencias de 'T1' con' [@ T1] 'y todas las ocurrencias de' T2' con '[@ T2]', y recibí este error de sintaxis en la ejecución: 'Msg 156, Nivel 15 , Estado 1, línea 34 Sintaxis incorrecta cerca de la palabra clave 'from'. –

0

Gracias por las respuestas, pero terminé usando un CTE, wgich Creo que es más limpio.

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

Robo de configuración de datos de @ isme, me escribió lo siguiente:

;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] 

Es decir, se crea un conjunto que contiene todos los posibles puntos finales de períodos (EPs), entonces "especie" ésos y asigne a cada uno un número de fila (OrderedEPs).

Luego, la consulta final ensambla cada par "adyacente" de filas juntas, y se une a las tablas originales para encontrar qué filas de cada una se superponen con el rango seleccionado.

Cuestiones relacionadas