PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

KESALAHAN:data tambahan setelah kolom terakhir yang diharapkan saat menggunakan PostgreSQL COPY

Meja kosong tidak bisa. Anda membutuhkan tabel yang cocok dengan struktur data input. Sesuatu seperti:

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

Anda tidak perlu mendeklarasikan tab sebagai DELIMITER karena itu defaultnya:

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

800 kolom katamu? Banyaknya kolom biasanya menunjukkan masalah dengan desain Anda. Bagaimanapun, ada cara untuk mengotomatiskan setengah dari CREATE TABLE naskah.

Otomasi

Dengan asumsi data mentah yang disederhanakan

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

Tentukan DELIMITER yang berbeda (salah satu yang tidak terjadi dalam data impor sama sekali), dan impor ke tabel staging sementara dengan satu text kolom:

CREATE TEMP TABLE tmp_data (raw text);

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

Kueri ini membuat CREATE TABLE naskah:

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

Kueri yang lebih umum &lebih aman:

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

Pengembalian:

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

Jalankan setelah memverifikasi validitas - atau jalankan secara dinamis jika Anda memercayai hasilnya:

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

Kemudian INSERT data dengan kueri ini:

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

Atau lebih sederhana dengan translate() :

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

String diubah menjadi literal baris, dilemparkan ke jenis baris tabel yang baru dibuat dan didekomposisi dengan (row).* .

Semua selesai.

Anda bisa memasukkan semua itu ke dalam fungsi plpgsql, tetapi Anda harus melindungi dari injeksi SQL. (Ada sejumlah solusi terkait di sini di SO. Coba cari.

db<>fiddle di sini
Fiddle SQL Lama



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana saya bisa mendapatkan fungsi jendela Redshift/Postgresql LAG untuk mengecualikan catatan secara selektif?

  2. Bagaimana cara mengenkripsi kata sandi dengan PostgreSQL?

  3. Menyimpan dan membandingkan kombinasi unik

  4. Tips untuk Memantau PostgreSQL untuk Moodle

  5. SQL domain ERROR:kolom tidak ada, pengaturan default