Pusty stół nie wystarczy. Potrzebujesz tabeli, która pasuje do struktury danych wejściowych. Coś takiego:
CREATE TABLE raw_data (
col1 int
, col2 int
...
);
Nie musisz deklarować tab
jako DELIMITER
ponieważ jest to ustawienie domyślne:
COPY raw_data FROM '/home/Projects/TestData/raw_data.txt';
800 kolumn mówisz? Tyle kolumn zwykle wskazuje na problem z projektem. W każdym razie są sposoby na półautomatyczną automatyzację CREATE TABLE
skrypt.
Automatyzacja
Zakładając uproszczone nieprzetworzone dane
1 2 3 4 -- first row contains "column names"
1 1 0 1 -- tab separated
1 0 0 1
1 0 1 1
Zdefiniuj inny DELIMITER
(taka, która w ogóle nie występuje w importowanych danych) i import do tymczasowej tabeli pomostowej z pojedynczym tekstem
kolumna:
CREATE TEMP TABLE tmp_data (raw text);
COPY tmp_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER '§');
To zapytanie tworzy CREATE TABLE
skrypt:
SELECT 'CREATE TABLE tbl (col' || replace (raw, E'\t', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t;
Bardziej ogólne i bezpieczniejsze zapytanie:
SELECT 'CREATE TABLE tbl('
|| string_agg(quote_ident('col' || col), ' bool, ' ORDER BY ord)
|| ' bool);'
FROM (SELECT raw FROM tmp_data LIMIT 1) t
, unnest(string_to_array(t.raw, E'\t')) WITH ORDINALITY c(col, ord);
Zwroty:
CREATE TABLE tbl (col1 bool, col2 bool, col3 bool, col4 bool);
Wykonaj po zweryfikowaniu poprawności - lub wykonaj dynamicznie, jeśli ufasz wynikowi:
DO
$$BEGIN
EXECUTE (
SELECT 'CREATE TABLE tbl (col' || replace(raw, ' ', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t
);
END$$;
Następnie WSTAW
dane z tym zapytaniem:
INSERT INTO tbl
SELECT (('(' || replace(replace(replace(
raw
, '1', 't')
, '0', 'f')
, E'\t', ',')
|| ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
Lub prościej dzięki translate()
:
INSERT INTO tbl
SELECT (('(' || translate(raw, E'10\t', 'tf,') || ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
Ciąg jest konwertowany na literał wiersza, rzutowany na nowo utworzony typ wiersza tabeli i rozkładany za pomocą (row).*
.
Wszystko gotowe.
Możesz to wszystko umieścić w funkcji plpgsql, ale musisz zabezpieczyć się przed wstrzyknięciem SQL. (W SO jest wiele powiązanych rozwiązań. Spróbuj wyszukać.
db<>fiddle tutaj
Stare skrzypce SQL