2009-10-20 20 views
10

Tengo dos selecciones y quiero combinarlas de tal manera que solo se devuelvan las filas únicas en ambas selecciones. ¿Hay alguna forma incorporada en Oracle 10g para lograr esto?Opuesto a INTERSECT en Oracle

Sé que puedo hacer algo como esto:

 
(select1 UNION select2) 
MINUS 
(select1 INTERSECT select2) 

pero me gustaría evitarlo. Tanto select1 como select2 tienen 20 líneas, por lo que esta forma sería realmente oscura y difícil de mantener.

+1

El nombre de este operador es 'diferencia simétrica' - con esto, Google da una serie de resultados (wich todos tienden a sugerir que esto no va a ser rápido). – AakashM

+0

No es un problema para mí si esto es lento.Este es un script por lotes para mi uso personal, no es necesario que sea súper eficiente. –

+0

¿Cómo son las dos selecciones? Es posible modificarlos, para que solo ejecute una selección y obtenga el resultado final. –

Respuesta

8

Si ambos select1 y select2 de retorno no hay duplicados, se puede usar algo como esto:

SELECT * FROM (select1 UNION ALL select2) a 
GROUP BY a.col1, a.col2, ... 
HAVING count(*) = 1 
1

Aquí hay otra idea:

  • hacer una combinación externa completa de select1 y select2
  • Uso solo aquellos registros con select1.id = NULL (registro solo en select2) o select2.ID = NULL (registro solo en select1)

así:

SELECT * 
FROM select1 FULL OUTER JOIN select2 on select1.id = select2.id 
WHERE select1.id is null or select2.id is null 
0
-- get not intersect data 
SELECT_FINAL 
WHERE FIELD_PK IS NOT IN(
    -- get ids of intersect 
    SELECT_AUX FIELD_PK1 FROM (
     SELECT1 
     INTERSECT 
     SELECT2 
    ) 
) 

lo hago

1

Esto funcionó para mí- no está seguro de lo rápido que es.

(select table_name from dba_tables where user = 'X' 
union 
select table_name from dba_tables where user = 'Y') 
minus 
(select table_name from dba_tables where user = 'X' 
intersect 
select table_name from dba_tables where user = 'Y') 
3

En Oracle 10g, tiene Common Table Expressions a su disposición.

WITH 
    select_1 AS (
    SELECT * 
    FROM your_table 
    WHERE your_condition = 1 
), 
    select_2 AS (
    SELECT * 
    FROM your_other_table 
    WHERE your_other_condition = 1 
) 
SELECT * FROM select_1 
UNION 
SELECT * FROM select_2 
MINUS 
(
    SELECT * FROM select_1 
    INTERSECT 
    SELECT * FROM select_2 
); 

Esto mantiene sus subconsultas mantenibles y el propósito de su consulta final clara.

Por supuesto, tener Oracle añadir un operador de SYM_DIFFERENCE a SQL sería aún mejor, pero no estoy conteniendo la respiración — que todavía no están convencidos de un tipo de datos BOOLEAN sería una buena idea.

0

Aquí hay otra solución, esta vez usando el análisis count() (Oracle 10 o posterior).

Ventajas:

  • podemos especificar qué columnas EXTRASECT en (por ejemplo KK1, KK2 en el ejemplo).
  • podemos seleccionar columnas sin clave (por ejemplo, NK1, NK2 ... en el ejemplo) que no es necesario que coincidamos.
  • plan eficiente.
  • Similar al ejemplo FULL OUTER JOIN, pero no obtenemos las columnas clave como campos separados que necesitan descodificación o mayúsculas o minúsculas para plegarlas juntas.

select KK1, KK2, NK1, NK2 from (select KK1, KK2, NK1, NK2, count(*) over(partition by KK1, KK2) cnt from (select KK1, KK2, NK1, NK2 from X union all select KK1, KK2, NK1, NK2 from Y)) where cnt = 1;