2011-12-21 18 views

risposta

45

Se il numero di campi nel CSV è costante, allora si potrebbe fare qualcosa di simile:

select a[1], a[2], a[3], a[4] 
from (
    select regexp_split_to_array('a,b,c,d', ',') 
) as dt(a) 

Ad esempio:

=> select a[1], a[2], a[3], a[4] from (select regexp_split_to_array('a,b,c,d', ',')) as dt(a); 
a | a | a | a 
---+---+---+--- 
a | b | c | d 
(1 row) 

Se il numero di campi nel CSV non è costante quindi è possibile ottenere il numero massimo di campi con qualcosa del genere:

select max(array_length(regexp_split_to_array(csv, ','), 1)) 
from your_table 

e quindi b uild l'appropriato elenco di colonne a[1], a[2], ..., a[M] per la tua query. Quindi, se il sopra ti ha dato un massimo di 6, devi usare questo:

select a[1], a[2], a[3], a[4], a[5], a[6] 
from (
    select regexp_split_to_array(csv, ',') 
    from your_table 
) as dt(a) 

è possibile combinare queste due domande in una funzione se si voleva.

Per esempio, dare questi dati (che è un NULL in ultima fila):

=> select * from csvs; 
    csv  
------------- 
1,2,3 
1,2,3,4 
1,2,3,4,5,6 

(4 rows) 

=> select max(array_length(regexp_split_to_array(csv, ','), 1)) from csvs; 
max 
----- 
    6 
(1 row) 

=> select a[1], a[2], a[3], a[4], a[5], a[6] from (select regexp_split_to_array(csv, ',') from csvs) as dt(a); 
a | a | a | a | a | a 
---+---+---+---+---+--- 
1 | 2 | 3 | | | 
1 | 2 | 3 | 4 | | 
1 | 2 | 3 | 4 | 5 | 6 
    | | | | | 
(4 rows) 

Dal momento che il delimitatore è una semplice stringa fissa, si potrebbe anche usare string_to_array invece di regexp_split_to_array:

select ... 
from (
    select string_to_array(csv, ',') 
    from csvs 
) as dt(a); 

Grazie a Michael per il promemoria su questa funzione.

Si dovrebbe davvero ridisegnare lo schema del database per evitare la colonna CSV se possibile. Dovresti utilizzare invece una colonna di array o una tabella separata.

+0

Grazie devono controllare e ripristinare – Gallop

+6

Considerare l'utilizzo di 'string_to_array' invece di' regexp_split_to_array'; dovrebbe essere più veloce poiché non ha il sovraccarico di elaborazione di espressioni regolari. – Michael

+1

@ Michael Puoi aggiungere un'altra risposta, se lo desideri. Oppure potrei aggiungere 'string_to_array' come opzione al mio, non so come mi sia mancato. –

64

split_part() fa ciò che si desidera in un unico passaggio:

SELECT split_part(col, ',', 1) AS col1 
    , split_part(col, ',', 2) AS col2 
    , split_part(col, ',', 3) AS col3 
    , split_part(col, ',', 4) AS col4 
FROM tbl; 

Aggiungi il maggior numero di linee come si dispone di elementi in col (il massimo possibile). Le colonne che superano gli elementi di dati saranno stringhe vuote ('').

+4

E sembrerebbe eseguire molto più velocemente rispetto alla versione regexp_split_to_array. –

+0

@ JohnBarça: tutte le funzioni di espressione regolare sono relativamente costose. Potente, ma per un prezzo ... –

+4

Legenda! Questo è di gran lunga l'approccio più veloce a questo tipo di problema. –

1

È possibile utilizzare la funzione di divisione.

SELECT 
    (select top 1 item from dbo.Split(FullName,',') where id=1) Column1, 
    (select top 1 item from dbo.Split(FullName,',') where id=2) Column2, 
    (select top 1 item from dbo.Split(FullName,',') where id=3) Column3, 
    (select top 1 item from dbo.Split(FullName,',') where id=4) Column4, 
    FROM MyTbl 
Problemi correlati