2011-09-26 15 views
18

UNION unisce due risultati e rimuove i duplicati, mentre UNION ALL non rimuove i duplicati. UNION ordina anche l'output finale.Sql Union Tutto * con * "distinto"

Quello che voglio è UNIONE TUTTI senza duplicati e senza il tipo. È possibile?

La ragione di ciò è che voglio che il risultato della prima query sia sopra il risultato finale e la seconda query in basso. (E ogni ordinato come se fossero in cui corrono individualmente)

+0

coSa fornitore SQL è questo? Non credo che lo standard richieda 'UNION ALL' generi qualsiasi cosa - in realtà il fatto che non lo ordina di solito ciò che lo rende una scelta migliore del semplice' UNION' – Romain

+0

@MikaelEriksson: Questo è quello che ha detto l'OP (anche se in un ordine confuso). Vuole fare un UNION ma non ha l'ordinamento implicito. – mwan

+0

@mwan - Hai ragione. Ho letto male la domanda. –

risposta

26

ho notato questa domanda ottiene un bel po 'di punti di vista così ho' Per prima cosa rivolgi una domanda che non hai richiesto !

Per quanto riguarda il titolo. Per ottenere un "Sql Union All con" distinto "", è sufficiente sostituire UNION ALL con UNION. Questo ha l'effetto di rimuovere i duplicati.

Per la vostra domanda specifica, dato il chiarimento "La prima query dovrebbe avere 'priorità', così i duplicati devono essere rimossi dal basso" è possibile utilizzare

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 esponendo l'ordinamento al chiamante è comunque una buona pratica. – onedaywhen

+0

@onedaywhen - Grazie per la modifica. Mi è mancato nella domanda. –

+0

Questo funziona se l'eliminazione di duplicati all'interno delle singole query è tutto ciò che è richiesto, ma non se è richiesta la rimozione di duplicati attraverso entrambe le query. –

0

L'ordinamento è utilizzata per eliminare i duplicati, ed è implicito DISTINCT e UNION query (ma non UNION ALL) - si potrebbe ancora specificare le colonne si preferisce ordinare da se ne hai bisogno ordinati per colonne specifiche.

Ad esempio, se si voleva ordinamento in base ai set di risultati, si potrebbe introdurre una colonna aggiuntiva, e ordinare da quel primo:

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

presumo le tabelle sono rispettivamente tabella1 e tabella2, e la tua soluzione è;

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

Non eliminerà tutte le righe che hanno duplicati? Penso piuttosto che vogliano solo rimuovere i duplicati! – onedaywhen

+0

Vedere la mia risposta per una correzione (sto usando SQL standard "EXCEPT" piuttosto che Oracle "MINUS" ma questa non è la correzione :) – onedaywhen

10

"UNION ordina anche l'output finale" - solo come un artefatto di implementazione. È per il che non è garantito il tipo di ordinamento e se è necessario un determinato ordinamento, è necessario specificarlo con una clausola ORDER BY. In caso contrario, l'ordine di output è quello che è più conveniente per il server.

Come tale, la richiesta di una funzione che esegue un UNION ALL ma che rimuove i duplicati è semplice: si chiama UNION.


Dal vostro chiarimento, si appaiono anche a credere che un UNION ALL restituirà tutti i risultati dalla prima query prima che i risultati delle query successive. Questo è anche non garantito. Ancora una volta, l'unico modo per ottenere un particolare ordine è specificarlo usando una clausola 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; 

Ma la vera risposta è: altro che la clausola di ORDER BY, l'ordinamento sarà da arbitraria e non garantiti.

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

Considerare questi tavoli (standard di codice SQL, gira su 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) 
    ), ... 

L'effetto desiderato è presente per ordinare tavolo A da col ascendente, sorta tavolo B da col scendendo poi unioning i due, rimuovendo i duplicati, mantenendo l'ordine prima dell'unione e lasciando la tabella A risultati sul "top" con tabella B sul "fondo" ad esempio (Codice pesudo)

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

Naturalmente, questo non funzionerà in SQL perché non ci può essere un solo ORDER BY clausola e può essere applicato soltanto alla espressione di tabella di livello superiore (o qualunque sia l'uscita di una query SELECT è noto come: lo chiamo "resultset").

La prima cosa da affrontare è l'intersezione tra le due tabelle, in questo caso i valori 4, 5 e 6. Come deve essere ordinato l'intersezione deve essere specificato nel codice SQL, quindi è auspicabile che anche il progettista lo specifichi! (cioè la persona che fa la domanda, in questo caso).

L'implicazione in questo caso sembrerebbe essere che l'intersezione ("duplicati") devono essere ordinati entro i risultati della tabella A. Pertanto, il gruppo di risultati ordinato dovrebbe essere simile a questo:

 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 in SQL "top" e "bottom" non hanno un significato inferito e una tabella (diversa da un set di risultati) non ha ordinamenti inerenti. Inoltre (per farla breve) considera che UNION rimuove le righe duplicate per implicazione e deve essere applicato prima di ORDER BY. La conclusione deve essere che l'ordinamento di ciascuna tabella deve essere definito in modo esplicito esponendo una/e colonna/i di ordinamento prima dell'unione di. Per questo possiamo usare la funzione con finestra ROW_NUMBER() ad es.

 ... 
    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

Mentre questo snippet di codice è benvenuto e potrebbe fornire un aiuto, sarebbe [notevolmente migliorato se includesse una spiegazione] (// meta.stackexchange.com/q/114762) di * come * affronta la domanda. Senza di ciò, la tua risposta ha un valore educativo molto inferiore - ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo per chi chiede ora! Si prega di [modificare] la risposta per aggiungere una spiegazione e fornire un'indicazione di quali limitazioni e ipotesi si applicano. –