2011-09-26 131 views
18

UNION une dos resultados y elimina los duplicados, mientras que UNION ALL no elimina los duplicados. UNION también ordena el resultado final.Sql Union All * with * "distinct"

Lo que quiero es el UNION ALL sin duplicados y sin el género. ¿Es eso posible?

La razón para esto es que quiero que el resultado de la primera consulta esté en la parte superior del resultado final y la segunda consulta en la parte inferior. (Y cada ordenan como si fueran ejecutar de forma individual)

+0

¿QUÉ proveedor SQL es esto? No creo que el estándar requiera que 'UNION ALL' ordene nada, de hecho, el hecho de que no lo clasifique es lo que lo hace una mejor opción que simplemente 'UNION' – Romain

+0

@MikaelEriksson: Eso es lo que dijo OP (aunque en un orden desordenado) Él quiere hacer una UNIÓN pero no tiene la clasificación implícita. – mwan

+0

@mwan - Tienes razón. Leí mal la pregunta. –

Respuesta

26

Me he dado cuenta esta cuestión se pone bastante una gran cantidad de puntos de vista, así que' Primero dirijo una pregunta que no hizo ¡pregunte!

En cuanto al título. Para lograr un "Sql Union All con" distinct "", simplemente reemplace UNION ALL con UNION. Esto tiene el efecto de eliminar duplicados.

Para su pregunta específica, dada la aclaración "La primera consulta debe tener 'prioridad', por lo que los duplicados deben ser retirados de fondo" se puede utilizar

SELECT col1, 
     col2, 
     MIN(grp) AS source_group 
FROM (SELECT 1 AS grp, 
       col1, 
       col2 
     FROM t1 
     UNION ALL 
     SELECT 2 AS grp, 
       col1, 
       col2 
     FROM t2) AS t 
GROUP BY col1, 
      col2 
ORDER BY MIN(grp), 
      col1 
+0

+1 exponer el orden de clasificación a la persona que llama es una buena práctica de todos modos. – onedaywhen

+0

@onedaywhen - Gracias por la edición. Perdió eso en la pregunta. –

+0

Esto funciona si lo único que se necesita es eliminar los duplicados en las consultas individuales, pero no si también es necesario eliminar los duplicados en ambas consultas. –

0

La especie se utiliza para eliminar los duplicados, y está implícito para DISTINCT y UNION consultas (pero no UNION ALL) - que aún se podía especificar las columnas que prefiere hacer su pedido por si los necesita ordenados por columnas específicas.

Por ejemplo, si desea la clasificación por los conjuntos de resultados, se puede introducir una columna adicional, y ordenar por que en primer lugar:

SELECT foo, bar, 1 as ResultSet 
FROM Foo 
WHERE bar = 1 
UNION 
SELECT foo, bar, 2 as ResultSet 
FROM Foo 
WHERE bar = 3 
UNION 
SELECT foo, bar, 3 as ResultSet 
FROM Foo 
WHERE bar = 2 
ORDER BY ResultSet 
0

que asumen sus tablas son tabla1 y tabla2, respectivamente, y su solución es;

(select * from table1 MINUS select * from table2) 
UNION ALL 
(select * from table2 MINUS select * from table1) 
+0

¿No eliminará esto todas las filas que tengan duplicados? ¡Prefiero pensar que solo quieren eliminar los duplicados! – onedaywhen

+0

Ver mi respuesta para una corrección (estoy usando 'EXCEPT' de SQL estándar en lugar de 'MENOS' de Oracle, pero esa no es la corrección :) – onedaywhen

10

"UNION también ordena el resultado final" - solo como un artefacto de implementación. Es por sin medios garantizados para realizar el tipo, y si necesita un orden de clasificación particular, debe especificarlo con una cláusula ORDER BY. De lo contrario, la orden de salida es la más conveniente para el servidor.

Como tal, su solicitud de una función que realiza un UNION ALL pero que elimina duplicados es fácil - se llama UNION.


Desde su aclaración, también parecen creer que un UNION ALL devolverá todos los resultados de la primera consulta antes de los resultados de las consultas posteriores. Esto es también no garantizado. Nuevamente, la única manera de lograr un orden en particular es especificarlo usando una cláusula ORDER BY.

1
SELECT *, 1 AS sort_order 
    FROM table1 
EXCEPT 
SELECT *, 1 AS sort_order 
    FROM table2 
UNION 
SELECT *, 1 AS sort_order 
    FROM table1 
INTERSECT 
SELECT *, 1 AS sort_order 
    FROM table2 
UNION 
SELECT *, 2 AS sort_order 
    FROM table2 
EXCEPT 
SELECT *, 2 AS sort_order 
    FROM table1 
ORDER BY sort_order; 

Pero la verdadera respuesta es: que no sea la cláusula ORDER BY, el orden de clasificación será por arbitraria y no está garantizada.

1
select T.Col1, T.Col2, T.Sort 
from 
    (
     select T.Col1, 
      T.Col2, 
      T.Sort, 
      rank() over(partition by T.Col1, T.Col2 order by T.Sort) as rn 
     from 
      (
      select Col1, Col2, 1 as Sort 
      from Table1 
      union all 
      select Col1, Col2, 2 
      from Table2 
     ) as T 
    ) as T 
where T.rn = 1  
order by T.Sort 
2

Considere estas tablas (código estándar SQL, se ejecuta en SQL Server 2008):

WITH A 
    AS 
    (
     SELECT * 
     FROM (
       VALUES (1), 
        (2), 
        (3), 
        (4), 
        (5), 
        (6) 
      ) AS T (col) 
    ), 
    B 
    AS 
    (
     SELECT * 
     FROM (
       VALUES (9), 
        (8), 
        (7), 
        (6), 
        (5), 
        (4) 
      ) AS T (col) 
    ), ... 

El efecto deseado es este para ordenar la tabla A por col ascendente, una especie de mesa B por col descendiendo luego unificante los dos, eliminar duplicados, conservar el orden antes de la unión y dejar los resultados de la tabla A en la "parte superior" con la tabla B en la parte inferior, por ejemplo (Código Pesudo)

(
SELECT * 
    FROM A 
    ORDER 
    BY col 
) 
UNION 
(
SELECT * 
    FROM B 
    ORDER 
    BY col DESC 
); 

Por supuesto, esto no funcionará en SQL porque no sólo puede haber un ORDER BY cláusula y que sólo se puede aplicar a la expresión de tabla de nivel superior (o cualquiera que sea el resultado de una consulta SELECT es conocido como; lo llamo el "conjunto de resultados").

Lo primero a tratar es la intersección entre las dos tablas, en este caso los valores 4, 5 y 6. ¡Cómo se debe ordenar la intersección debe especificarse en el código SQL, por lo tanto, es deseable que el diseñador también lo especifique! (es decir, la persona que hace la pregunta, en este caso).

La implicación en este caso, parece ser que la intersección ("duplicados") deben clasificarse dentro de los resultados de la tabla A. Por lo tanto, el conjunto de resultados ordenada debe tener este aspecto:

 VALUES (1), -- A including intersection, ascending 
      (2), -- A including intersection, ascending 
      (3), -- A including intersection, ascending 
      (4), -- A including intersection, ascending 
      (5), -- A including intersection, ascending 
      (6), -- A including intersection, ascending 
      (9), -- B only, descending 
      (8), -- B only, descending 
      (7), -- B only, descending 

Nota de SQL "superior" e "inferior" no tienen un significado diferente y una tabla (que no sea un conjunto de resultados) no tiene un orden inherente. Además (para abreviar, considere que UNION elimina las filas duplicadas por implicación y debe aplicarse antes de ORDER BY. La conclusión debe ser que el orden de clasificación de cada tabla debe definirse explícitamente al exponer una (s) columna (s) de orden de clasificación antes de que estén unidas. Para esto, podemos usar la función de ventana ROW_NUMBER(), p.

 ... 
    A_ranked 
    AS 
    (
     SELECT col, 
      ROW_NUMBER() OVER (ORDER BY col) AS sort_order_1 
     FROM A      -- include the intersection 
    ), 
    B_ranked 
    AS 
    (
     SELECT *, 
      ROW_NUMBER() OVER (ORDER BY col DESC) AS sort_order_1 
     FROM B 
     WHERE NOT EXISTS (   -- exclude the intersection 
         SELECT * 
          FROM A 
          WHERE A.col = B.col 
         ) 
    ) 
SELECT *, 1 AS sort_order_0 
    FROM A_ranked 
UNION 
SELECT *, 2 AS sort_order_0 
    FROM B_ranked 
ORDER BY sort_order_0, sort_order_1; 
0

1,1: select 1 from dual union all select 1 from dual 1: select 1 from dual union select 1 from dual

+2

Si bien este fragmento de código es bienvenido, y puede proporcionar algo de ayuda, sería [muy mejorado si incluía una explicación] (// meta.stackexchange.com/q/114762) de * cómo * aborda la pregunta. Sin eso, tu respuesta tiene mucho menos valor educativo: recuerda que estás respondiendo la pregunta a los lectores en el futuro, ¡no solo a la persona que pregunta ahora! Por favor [edite] su respuesta para agregar una explicación y dar una indicación de qué limitaciones y suposiciones se aplican. –