Een lege tafel is niet voldoende. U hebt een tabel nodig die overeenkomt met de structuur van invoergegevens. Iets als:
CREATE TABLE raw_data (
col1 int
, col2 int
...
);
U hoeft tab
niet te declareren als DELIMITER
aangezien dat de standaard is:
COPY raw_data FROM '/home/Projects/TestData/raw_data.txt';
800 kolommen zegt u? Zoveel kolommen duiden doorgaans op een probleem met uw ontwerp. Hoe dan ook, er zijn manieren om de CREATE TABLE
voor de helft te automatiseren schrift.
Automatisering
Uitgaande van vereenvoudigde onbewerkte gegevens
1 2 3 4 -- first row contains "column names"
1 1 0 1 -- tab separated
1 0 0 1
1 0 1 1
Definieer een andere DELIMITER
(een die helemaal niet voorkomt in de importgegevens), en importeer naar een tijdelijke verzameltabel met een enkele text
kolom:
CREATE TEMP TABLE tmp_data (raw text);
COPY tmp_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER '§');
Deze query maakt de CREATE TABLE
script:
SELECT 'CREATE TABLE tbl (col' || replace (raw, E'\t', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t;
Een meer algemene en veiligere vraag:
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);
Retourneren:
CREATE TABLE tbl (col1 bool, col2 bool, col3 bool, col4 bool);
Uitvoeren na verificatie van de geldigheid - of dynamisch uitvoeren als u het resultaat vertrouwt:
DO
$$BEGIN
EXECUTE (
SELECT 'CREATE TABLE tbl (col' || replace(raw, ' ', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t
);
END$$;
Dan INSERT
de gegevens met deze vraag:
INSERT INTO tbl
SELECT (('(' || replace(replace(replace(
raw
, '1', 't')
, '0', 'f')
, E'\t', ',')
|| ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
Of eenvoudiger met translate()
:
INSERT INTO tbl
SELECT (('(' || translate(raw, E'10\t', 'tf,') || ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
De tekenreeks wordt geconverteerd naar een letterlijke rij, gecast naar het nieuw gemaakte tabelrijtype en ontleed met (row).*
.
Alles klaar.
Je zou dat allemaal in een plpgsql-functie kunnen stoppen, maar je zou je moeten beschermen tegen SQL-injectie. (Er zijn een aantal gerelateerde oplossingen hier op SO. Probeer een zoekopdracht.
db<>fiddle hier
Oude SQL Fiddle