Solución:
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 necesitas declarar tab
como DELIMITER
ya que ese es el 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
texto.
Automatización
Suponiendo datos brutos simplificados
1 2 3 4 -- first row contains "column names"
1 1 0 1 -- tab separated
1 0 0 1
1 0 1 1
Definir una diferente DELIMITER
(uno que no ocurre 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
texto:
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);
Ejecute después de verificar la validez, o ejecute 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'10t', '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 una serie de soluciones relacionadas aquí en SO. Intente una búsqueda.
db <> violín aquí
Viejo violín SQL