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