Un tavolo vuoto non va bene. Hai bisogno di una tabella che corrisponda alla struttura dei dati di input. Qualcosa come:
CREATE TABLE raw_data (
col1 int
, col2 int
...
);
Non è necessario dichiarare tab
come DELIMITER
poiché è l'impostazione predefinita:
COPY raw_data FROM '/home/Projects/TestData/raw_data.txt';
800 colonne dici? Quelle colonne in genere indicherebbero un problema con il tuo design. Ad ogni modo, ci sono modi per automatizzare a metà il CREATE TABLE
copione.
Automazione
Assumendo dati grezzi semplificati
1 2 3 4 -- first row contains "column names"
1 1 0 1 -- tab separated
1 0 0 1
1 0 1 1
Definisci un diverso DELIMITER
(uno che non si trova affatto nei dati di importazione) e importare in una tabella di staging temporanea con un singolo text
colonna:
CREATE TEMP TABLE tmp_data (raw text);
COPY tmp_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER '§');
Questa query crea il CREATE TABLE
sceneggiatura:
SELECT 'CREATE TABLE tbl (col' || replace (raw, E'\t', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t;
Una query più generica e più sicura:
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);
Resi:
CREATE TABLE tbl (col1 bool, col2 bool, col3 bool, col4 bool);
Esegui dopo aver verificato la validità o esegui dinamicamente se ritieni attendibile il risultato:
DO
$$BEGIN
EXECUTE (
SELECT 'CREATE TABLE tbl (col' || replace(raw, ' ', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t
);
END$$;
Quindi INSERT
i dati con questa query:
INSERT INTO tbl
SELECT (('(' || replace(replace(replace(
raw
, '1', 't')
, '0', 'f')
, E'\t', ',')
|| ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
O più semplice con translate()
:
INSERT INTO tbl
SELECT (('(' || translate(raw, E'10\t', 'tf,') || ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
La stringa viene convertita in una riga letterale, convertita nel tipo di riga della tabella appena creato e scomposta con (row).*
.
Tutto fatto.
Potresti mettere tutto questo in una funzione plpgsql, ma dovresti proteggerti dall'iniezione SQL. (Ci sono una serie di soluzioni correlate qui su SO. Prova una ricerca.
db<>violino qui
Old SQL Fiddle