PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

ГРЕШКА:допълнителни данни след последната очаквана колона при използване на PostgreSQL COPY

Празна маса няма да свърши работа. Нуждаете се от таблица, която отговаря на структурата на входните данни. Нещо като:

CREATE TABLE raw_data (
  col1 int
, col2 int
  ...
);

Не е необходимо да декларирате tab като DELIMITER тъй като това е по подразбиране:

COPY raw_data FROM '/home/Projects/TestData/raw_data.txt';

800 колони казвате? Толкова много колони обикновено показват проблем с вашия дизайн. Както и да е, има начини за полуавтоматизиране на CREATE TABLE скрипт.

Автоматизация

Приемайки опростени необработени данни

1   2   3   4  -- first row contains "column names"
1   1   0   1  -- tab separated
1   0   0   1
1   0   1   1

Дефинирайте различен DELIMITER (това, което изобщо не се среща в данните за импортиране) и импортиране към временна междинна таблица с един текст колона:

CREATE TEMP TABLE tmp_data (raw text);

COPY tmp_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER '§');

Тази заявка създава CREATE TABLE скрипт:

SELECT 'CREATE TABLE tbl (col' || replace (raw, E'\t', ' bool, col') || ' bool)'
FROM   (SELECT raw FROM tmp_data LIMIT 1) t;

По-генерична и по-безопасна заявка:

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);

Връща:

CREATE TABLE tbl (col1 bool, col2 bool, col3 bool, col4 bool);

Изпълнете след проверка на валидността - или изпълнете динамично, ако имате доверие на резултата:

DO
$$BEGIN
EXECUTE (
   SELECT 'CREATE TABLE tbl (col' || replace(raw, ' ', ' bool, col') || ' bool)'
   FROM  (SELECT raw FROM tmp_data LIMIT 1) t
   );
END$$;

След това INSERT данните с тази заявка:

INSERT INTO tbl
SELECT (('(' || replace(replace(replace(
                  raw
                , '1',   't')
                , '0',   'f')
                , E'\t', ',')
             || ')')::tbl).*
FROM   (SELECT raw FROM tmp_data OFFSET 1) t;

Или по-просто с translate() :

INSERT INTO tbl
SELECT (('(' || translate(raw, E'10\t', 'tf,') || ')')::tbl).*
FROM   (SELECT raw FROM tmp_data OFFSET 1) t;

Низът се преобразува в литерал на ред, преобразува се в новосъздадения тип ред на таблицата и се разлага с (row).* .

Готово.

Можете да поставите всичко това във функция plpgsql, но ще трябва да се предпазите срещу SQL инжектиране. (Тук в SO има редица свързани решения. Опитайте с търсене.

db<>fiddle тук
Стар SQL Fiddle



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL заявка за списък с разрешени стойности в ограничение?

  2. Значи инсталирах postgresql и localhost порт в конфликт с ruby ​​приложението?

  3. Как да вмъкнете стойности „NULL“ в база данни на PostgreSQL с помощта на Python?

  4. Низови литерали и escape знаци в postgresql

  5. Премахнете двойката ключ стойност от jsonb вложен масив в postgresql