列の数がcsvファイルで不明な一時テーブルにcsvファイルをコピーする方法があるかどうか疑問に思っています。私が使用しているDBソフトウェアはPgAdmin IIIです。列の数がわかっている場合は、その列数の一時テーブルを作成し、csvファイルを次のようにコピーできることを理解しました。
CREATE TEMPORARY TABLE temp
(
col1 VARCHAR(80),
col2 VARCHAR(80),
....
coln VARCHAR(80)
);
COPY temp FROM 'C:/Users/postgres/Boost.txt' CSV HEADER DELIMITER E' '
ただし、一時テーブルに列のない一時テーブルにcsvファイルを単にコピーしようとすると、Postgresql(バージョン8.4)は、csvファイルよりも列が少ないテーブルで作業していると不平を言います。私は調査しており、これについてPostgresqlのドキュメントで何も見つけることができないようです。 Postgresqlで実行時に決定された任意の数の列を持つ一時テーブルにcsvファイルをコピーできるかどうか誰かが知っていますか?一時テーブルにcsvファイルが読み込まれたら、破棄される前に一時テーブルを使用して他のテーブルとの比較を行う予定です。また、csvファイルの最初の行にはヘッダーが含まれています。
基本:
PROGRAM
の後のCOPY
およびGET DIAGNOSTICS
のCOPY
句には、Postgres9.3 +が必要です。format()
Postgresが必要9.1 +head
コマンドを除きます。 Windowsバージョンの場合、以下を考慮してください。この関数はanyテーブル構造を完全に動的にコピーします:
CREATE OR REPLACE FUNCTION f_dynamic_copy(_file text
, _tbl text = 'tmp1'
, _delim text = E'\t'
, _nodelim text = chr(127)) -- see below!
RETURNS text AS
$func$
DECLARE
row_ct int;
BEGIN
-- create staging table for 1st row as single text column
CREATE TEMP TABLE tmp0(cols text) ON COMMIT DROP;
-- fetch 1st row
EXECUTE format($$COPY tmp0 FROM PROGRAM 'head -n1 %I' WITH (DELIMITER %L)$$ -- impossible delimiter
, _file, _nodelim);
-- create actual temp table with all columns text
EXECUTE (
SELECT format('CREATE TEMP TABLE %I(', _tbl)
|| string_agg(quote_ident(col) || ' text', ',')
|| ')'
FROM (SELECT cols FROM tmp0 LIMIT 1) t
, unnest(string_to_array(t.cols, E'\t')) col
);
-- Import data
EXECUTE format($$COPY %I FROM %L WITH (FORMAT csv, HEADER, NULL '\N', DELIMITER %L)$$
, _tbl, _file, _delim);
GET DIAGNOSTICS row_ct = ROW_COUNT;
RETURN format('Created table %I with %s rows.', _tbl, row_ct);
END
$func$ LANGUAGE plpgsql;
コールバリアント:
SELECT f_dynamic_copy('/path/to/file.csv');
SELECT f_dynamic_copy('/path/to/file2.csv', 'tmp_file2');
SELECT f_dynamic_copy(_file => '/path/to/file2.csv'
, _tbl => 'tmp_file2');
, _delim => E'\t'); -- using assignment operator since pg 9.5
回答:
123行のテーブルtmp_file2を作成しました。
メインのCOPY
の前に、予備のCOPY ... TO tmp0
を実行して、列名を含む最初の行をフェッチします。これは、引用符で囲まれていないことが想定され、COPY ... TO ... (FORMAT csv, HEADER)
などの大文字と小文字を区別する文字列はそれらをエクスポートします。
実際のターゲットテーブルの構造は、すべての列がデータ型text
であるテーブルから派生します。結果のテーブルのデフォルト名はtmp1
です-または、独自の2番目の関数パラメーターを指定します。
次に、COPY
が実行されます。デフォルトの区切り文字はタブ文字です。または3番目の関数パラメーターとして区切り文字を指定します。
CSVファイルの最初の行に表示されない区切り文字以外の_nodelim
には、任意の1バイト文字を使用します。 制御文字「削除」(ASCII 127) を任意に選択しています。その文字はここでSOに飲み込まれるため、代わりにchr(127)
を使用して生成しますが、これも有効です。文字がポップアップしないと仮定します-または、区切り文字を4番目の関数パラメーターとして指定します。
この関数は、テーブル名とインポートされた行の数を返します。
セッションの終了時に一時テーブルが終了することを忘れないでください。
PROGRAM
を使用してコマンドを実行すると、SELinuxなどのオペレーティングシステムのアクセス制御メカニズムによって制限される場合があります。
SOの関連回答:
そのバージョンは古すぎる 、ここまでバックポートするつもりはありません。
GET DIAGNOSTICS
はオプション機能です。そのままにするか、テーブルの全数に置き換えることができます
9.3ページのPROGRAM
のCOPY
句の原始的な(高価な)代替手段は、代わりに完全なテーブルをインポートすることです。
EXECUTE format($$COPY tmp0 FROM %L WITH (DELIMITER %L)$$, _file, _delim);
または、2番目の入力ファイルを準備するか、シェルからパイプすることによってそれを機能させることができます。COPY tablename FROM STDIN
は8.4ページで使用できます。
format()
は、プレーンな文字列連結で置き換えることができます。ただし、SQLインジェクションには注意してください。このプログラムは、ほとんどすべてのCSVまたはJSONに基づくPostgreSQLテーブルの作成を1行で処理します。