2011-12-21 14 views

Odpowiedz

45

Jeżeli liczba pól w pliku CSV jest stała wtedy mógłby zrobić coś takiego:

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

Na przykład:

=> 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) 

Jeżeli liczba pól w pliku CSV nie jest stała następnie można uzyskać maksymalną liczbę pól z czymś podobnym:

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

, a następnie b uild odpowiednią kolumnę a[1], a[2], ..., a[M] dla zapytania. Więc jeśli powyższe dało ci maksimum 6, użyłbyś tego:

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) 

Możesz połączyć te dwa zapytania w funkcję, jeśli chcesz.

Na przykład podać te dane (to jest NULL w ostatnim rzędzie):

=> 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) 

Ponieważ separatorem jest prosty ustalony ciąg, można również użyć string_to_array zamiast regexp_split_to_array:

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

Dzięki Michael za przypomnienie o tej funkcji.

Naprawdę powinieneś przeprojektować swój schemat bazy danych, aby uniknąć kolumny CSV, jeśli w ogóle jest to możliwe. Zamiast tego powinieneś używać kolumny tablicowej lub oddzielnej tabeli.

+0

Dzięki powinien sprawdzić i powrócić – Gallop

+6

Rozważ użycie 'string_to_array' zamiast' regexp_split_to_array'; powinien być szybszy, ponieważ nie ma narzutu przetwarzania wyrażenia regularnego. – Michael

+1

@Michael Możesz dodać to jako inną odpowiedź, jeśli chcesz. Albo mogę dodać "string_to_array" jako opcję w mojej, nie wiem, jak to przegapiłem. –

64

split_part() robi to, co chcesz w jednym kroku:

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; 

Dodaj wiele linii, jak masz produktów w col (możliwego maksimum). Kolumny przekraczające pozycje danych będą pustymi ciągami ('').

+4

Wygląda na to, że będzie działać dużo szybciej niż wersja regexp_split_to_array. –

+0

@ JohnBarça: Wszystkie funkcje wyrażenia regularnego są stosunkowo drogie. Potężny, ale za cenę ... –

+4

Legenda! Jest to zdecydowanie najszybsze podejście do tego rodzaju problemu. –

1

Możesz użyć funkcji podziału.

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 
Powiązane problemy