Prázdný stůl nebude stačit. Potřebujete tabulku, která odpovídá struktuře vstupních dat. Něco jako:
CREATE TABLE raw_data (
col1 int
, col2 int
...
);
tab
nemusíte deklarovat jako DELIMITER
protože to je výchozí:
COPY raw_data FROM '/home/Projects/TestData/raw_data.txt';
800 sloupců, říkáte? Tolik sloupců by obvykle znamenalo problém s vaším návrhem. Každopádně existují způsoby, jak napůl automatizovat CREATE TABLE
skript.
Automatizace
Za předpokladu zjednodušených nezpracovaných dat
1 2 3 4 -- first row contains "column names"
1 1 0 1 -- tab separated
1 0 0 1
1 0 1 1
Definujte jiný DELIMITER
(takový, který se v importovaných datech vůbec nevyskytuje) a import do dočasné pracovní tabulky s jediným textem
sloupec:
CREATE TEMP TABLE tmp_data (raw text);
COPY tmp_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER '§');
Tento dotaz vytvoří CREATE TABLE
skript:
SELECT 'CREATE TABLE tbl (col' || replace (raw, E'\t', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t;
Obecnější a bezpečnější dotaz:
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);
Vrátí:
CREATE TABLE tbl (col1 bool, col2 bool, col3 bool, col4 bool);
Spustit po ověření platnosti – nebo provést dynamicky, pokud výsledku důvěřujete:
DO
$$BEGIN
EXECUTE (
SELECT 'CREATE TABLE tbl (col' || replace(raw, ' ', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t
);
END$$;
Poté INSERT
data s tímto dotazem:
INSERT INTO tbl
SELECT (('(' || replace(replace(replace(
raw
, '1', 't')
, '0', 'f')
, E'\t', ',')
|| ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
Nebo jednodušší pomocí translate()
:
INSERT INTO tbl
SELECT (('(' || translate(raw, E'10\t', 'tf,') || ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
Řetězec je převeden na řádkový literál, přetypován na nově vytvořený typ řádku tabulky a rozložen pomocí (řádek).*
.
Vše hotovo.
To vše byste mohli vložit do funkce plpgsql, ale museli byste se chránit před injekcí SQL. (Zde na SO je řada souvisejících řešení. Zkuste hledat.
db<>fiddle zde
Old SQL Fiddle