2014-06-10 15 views
6

Ho due matrici in PostgreSQL che devo unire. Per esempio:Unione di due array in PostgreSQL senza problemi.

{1,2,3} unione {1,4,5} sarebbero tornati {1,2,3,4,5}

Utilizzando la concatenate (||) operatore non eliminerebbe le voci duplicate, cioè restituisce {1,2,3,1,4,5}

ho trovato una soluzione sul web, però lo faccio non mi piace come si deve UNNEST entrambi gli array: select ARRAY(select unnest(ARRAY[1,2,3]) as a UNION select unnest(ARRAY[2,3,4,5]) as a)

esiste un operatore o funzione built-in che sarà modo pulito sindacali due array?

+0

Non credo che ci siano operatori set-saggio o funzioni per gli array, c'è una domanda simile [su intersezioni oltre qui] (http://stackoverflow.com/q/7020264/479863), probabilmente si potrebbe adattare la soluzione. –

+0

@muistooshort Ci sono un sacco di operatore di serie per gli array http://www.postgresql.org/docs/9.1/static/functions-array.html – MrGlass

+1

'@>' e '<@' non realmente qualificarsi come * Un sacco*. O mi sta sfuggendo qualcosa? –

risposta

11

Se il problema è quello di UNNEST due volte questo sarà UNNEST solo una volta

select array_agg(a order by a) 
from (
    select distinct unnest(array[1,2,3] || array[2,3,4,5]) as a 
) s; 
+1

in funzione '' 'CREATE OR REPLACE mergeArrays Funzione (A1 anyarray, anyarray a2) restituisce anyarray AS $$ \t SELEZIONA array_agg (x ORDER BY x) \t DA ( \t \t SELEZIONA UNNEST DISTINCT ($ 1 || $ 2) AS x \t) s; $$ LINGUA SQL STRICT; '' ' –

9

C'è un'estensione intarray (nella confezione contrib) che contiene alcune funzioni e gli operatori utili:

postgres=# create extension intarray ; 
CREATE EXTENSION 

con singolo operatore di pipe:

postgres=# select array[1,2,3] | array[3,4,5]; 
    ?column? 
───────────── 
{1,2,3,4,5} 
(1 row) 

o con uniq funzione:

postgres=# select uniq(ARRAY[1,2,3] || ARRAY[3,4,5]); 
    uniq  
───────────── 
{1,2,3,4,5} 
(1 row) 

ANSI/SQL conosce un multiset, ma non è supportato da PostgreSQL ancora.

+0

Grazie, ma il mio caso del mondo reale non è in realtà con numeri interi, quindi intarray non mi aiuterà – MrGlass

+0

@MrGlass quindi è necessario scrivere la propria estensione. ma, non penso, così tanto ingiusto ha troppo in alto overhead. Unisci 100K valori ha bisogno di circa 123ms sul mio Lenovo T520. Qualsiasi estensione non dovrebbe essere significativamente più veloce. UNNEST, UNION ALL sono veloci. –

+0

Sì, la risposta potrebbe essere che questo è il metodo migliore. Speravo solo di aver perso qualcosa :) – MrGlass

1

Può essere fatto in questo modo ...

select uniq(sort(array_remove(array_cat(ARRAY[1,2,3], ARRAY[1,4,5]), NULL))) 

dà:

{1,2,3,4,5} 

array_remove è necessaria perché il vostro non può ordinare le matrici con NULLS. L'ordinamento è necessario perché uniq de-duplica solo se vengono trovati elementi adiacenti.

Un vantaggio di questo approccio rispetto @Clodoaldo Neto di è che funziona tutto all'interno della selezione, e non fa il unnest nella clausola FROM. Ciò rende più semplice operare su più colonne di array contemporaneamente e in una singola scansione di tabella. (Anche se vedi la versione di Ryan Guill come una funzione nel commento).

Inoltre, questo modello funziona per tutti i tipi di array (che è elementi sono ordinabili).

Un inconveniente è che, tenerne, è un po 'più lento per gli array più lunghi (per l'ordinamento e le 3 allocazioni matrice intermedie).

penso sia questo e il accetta risposta fallire se si desidera mantenere NULL nel risultato.