Una mesa vacía no servirá. Necesita una tabla que coincida con la estructura de los datos de entrada. Algo como:
CREATE TABLE raw_data (
col1 int
, col2 int
...
);
No es necesario declarar tab
como DELIMITER
ya que ese es el valor predeterminado:
COPY raw_data FROM '/home/Projects/TestData/raw_data.txt';
800 columnas dices? Esa cantidad de columnas normalmente indicaría un problema con su diseño. De todos modos, hay formas de automatizar a medias el CREATE TABLE
guión.
Automatización
Suponiendo datos sin procesar simplificados
1 2 3 4 -- first row contains "column names"
1 1 0 1 -- tab separated
1 0 0 1
1 0 1 1
Defina un DELIMITER
diferente (uno que no ocurre en absoluto en los datos de importación) e importar a una tabla de preparación temporal con un solo text
columna:
CREATE TEMP TABLE tmp_data (raw text);
COPY tmp_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER '§');
Esta consulta crea el CREATE TABLE
guión:
SELECT 'CREATE TABLE tbl (col' || replace (raw, E'\t', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t;
Una consulta más genérica y segura:
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);
Devoluciones:
CREATE TABLE tbl (col1 bool, col2 bool, col3 bool, col4 bool);
Ejecutar después de verificar la validez, o ejecutar dinámicamente si confía en el resultado:
DO
$$BEGIN
EXECUTE (
SELECT 'CREATE TABLE tbl (col' || replace(raw, ' ', ' bool, col') || ' bool)'
FROM (SELECT raw FROM tmp_data LIMIT 1) t
);
END$$;
Luego INSERT
los datos con esta consulta:
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 más simple con translate()
:
INSERT INTO tbl
SELECT (('(' || translate(raw, E'10\t', 'tf,') || ')')::tbl).*
FROM (SELECT raw FROM tmp_data OFFSET 1) t;
La cadena se convierte en un literal de fila, se convierte en el tipo de fila de la tabla recién creada y se descompone con (row).*
.
Todo listo.
Podría poner todo eso en una función plpgsql, pero necesitaría protegerse contra la inyección de SQL. (Hay varias soluciones relacionadas aquí en SO. Intente realizar una búsqueda.
db<>fiddle aquí
Viejo SQL Fiddle