私はnyummy
という名前のデータベーススキーマとcimory
という名前のテーブルを持っています:
create table nyummy.cimory (
id numeric(10,0) not null,
name character varying(60) not null,
city character varying(50) not null,
CONSTRAINT cimory_pkey PRIMARY KEY (id)
);
cimory
テーブルのデータをSQLスクリプトファイルの挿入としてエクスポートしたい。ただし、市が「東京」に等しいレコード/データのみをエクスポートします(市のデータはすべて小文字であると仮定します)。
どうやってするの?
ソリューションがフリーウェアのGUIツールであるかコマンドラインであるかは関係ありません(GUIツールソリューションの方が優れています)。 pgAdmin IIIを試しましたが、これを行うオプションが見つかりません。
エクスポートするセットでテーブルを作成し、コマンドラインユーティリティpg_dumpを使用してファイルにエクスポートします。
create table export_table as
select id, name, city
from nyummy.cimory
where city = 'tokyo'
$ pg_dump --table=export_table --data-only --column-inserts my_database > data.sql
--column-inserts
は、列名を持つ挿入コマンドとしてダンプします。
--data-only
はスキーマをダンプしません。
以下にコメントするように、テーブルの代わりにビューを作成すると、新しいエクスポートが必要なときにテーブルを作成する必要がなくなります。
data-only exportの場合 COPY
を使用します=。
1行に1つのテーブル行を含むファイルをプレーンテキスト(INSERT
コマンドではない)として取得します。ファイルは小さくて高速です。
COPY (SELECT * FROM nyummy.cimory WHERE city = 'tokio') TO '/path/to/file.csv';
Import同じ構造の別のテーブルに同じものをどこでも:
COPY other_tbl FROM '/path/to/file.csv';
COPY
は、サーバーにローカルファイルを読み書きします。これは、クライアントにローカルファイルを読み書きするpg_dump
やpsql
などのクライアントプログラムとは異なります 。両方が同じマシンで実行されている場合、それは重要ではありませんが、リモート接続では実行されます。
Psqlの \copy
コマンド もあります:
フロントエンド(クライアント)コピーを実行します。これはSQL
COPY
コマンドを実行する操作ですが、サーバーが指定されたファイルを読み書きする代わりに、psqlはファイルを読み書きし、サーバーとローカルファイルシステム間でデータをルーティングします。これは、ファイルのアクセス可能性と特権がサーバーではなくローカルユーザーのものであり、SQLスーパーユーザー特権が必要ないことを意味します。
これは簡単で高速pgAdminを使用してテーブルをスクリプトにエクスポート手動で追加インストールなしでにする方法です。
このメソッドは、@ Clodoaldo Netoの回答で示されているように、export_tableを作成する手法とも連携します。
SQL Workbench にはそのような機能があります。
クエリを実行した後、クエリ結果を右クリックし、「SQLとしてデータをコピー> SQL挿入」を選択します
私のユースケースでは、単純にgrepにパイプすることができました。
pg_dump -U user_name --data-only --column-inserts -t nyummy.cimory | grep "tokyo" > tokyo.sql
@PhilHibbsコードに基づいて、別の方法でそれを行うプロシージャを記述しようとしました。見て、テストしてください。
CREATE OR REPLACE FUNCTION dump(IN p_schema text, IN p_table text, IN p_where text)
RETURNS setof text AS
$BODY$
DECLARE
dumpquery_0 text;
dumpquery_1 text;
selquery text;
selvalue text;
valrec record;
colrec record;
BEGIN
-- ------ --
-- GLOBAL --
-- build base INSERT
-- build SELECT array[ ... ]
dumpquery_0 := 'INSERT INTO ' || quote_ident(p_schema) || '.' || quote_ident(p_table) || '(';
selquery := 'SELECT array[';
<<label0>>
FOR colrec IN SELECT table_schema, table_name, column_name, data_type
FROM information_schema.columns
WHERE table_name = p_table and table_schema = p_schema
ORDER BY ordinal_position
LOOP
dumpquery_0 := dumpquery_0 || quote_ident(colrec.column_name) || ',';
selquery := selquery || 'CAST(' || quote_ident(colrec.column_name) || ' AS TEXT),';
END LOOP label0;
dumpquery_0 := substring(dumpquery_0 ,1,length(dumpquery_0)-1) || ')';
dumpquery_0 := dumpquery_0 || ' VALUES (';
selquery := substring(selquery ,1,length(selquery)-1) || '] AS MYARRAY';
selquery := selquery || ' FROM ' ||quote_ident(p_schema)||'.'||quote_ident(p_table);
selquery := selquery || ' WHERE '||p_where;
-- GLOBAL --
-- ------ --
-- ----------- --
-- SELECT LOOP --
-- execute SELECT built and loop on each row
<<label1>>
FOR valrec IN EXECUTE selquery
LOOP
dumpquery_1 := '';
IF not found THEN
EXIT ;
END IF;
-- ----------- --
-- LOOP ARRAY (EACH FIELDS) --
<<label2>>
FOREACH selvalue in ARRAY valrec.MYARRAY
LOOP
IF selvalue IS NULL
THEN selvalue := 'NULL';
ELSE selvalue := quote_literal(selvalue);
END IF;
dumpquery_1 := dumpquery_1 || selvalue || ',';
END LOOP label2;
dumpquery_1 := substring(dumpquery_1 ,1,length(dumpquery_1)-1) || ');';
-- LOOP ARRAY (EACH FIELD) --
-- ----------- --
-- debug: RETURN NEXT dumpquery_0 || dumpquery_1 || ' --' || selquery;
-- debug: RETURN NEXT selquery;
RETURN NEXT dumpquery_0 || dumpquery_1;
END LOOP label1 ;
-- SELECT LOOP --
-- ----------- --
RETURN ;
END
$BODY$
LANGUAGE plpgsql VOLATILE;
その後 :
-- for a range
SELECT dump('public', 'my_table','my_id between 123456 and 123459');
-- for the entire table
SELECT dump('public', 'my_table','true');
私のpostgres 9.1で、混合フィールドデータ型(タイムゾーンなしのtext、double、int、timestampなど)のテーブルでテストしました。
そのため、TEXT型のCASTが必要です。私のテストは約9M行で正しく実行され、実行の18分前に失敗するようです。
ps:WEBでmysqlに相当するものを見つけました。
特定のレコードでテーブルを表示してから、sqlファイルをダンプできます
CREATE VIEW foo AS
SELECT id,name,city FROM nyummy.cimory WHERE city = 'tokyo'
これを行うための簡単な手順をノックアップしました。それは単一の行に対してのみ機能するため、必要な行を選択するだけの一時ビューを作成し、pg_temp.temp_viewを実際に挿入するテーブルに置き換えます。
CREATE OR REPLACE FUNCTION dv_util.gen_insert_statement(IN p_schema text, IN p_table text)
RETURNS text AS
$BODY$
DECLARE
selquery text;
valquery text;
selvalue text;
colvalue text;
colrec record;
BEGIN
selquery := 'INSERT INTO ' || quote_ident(p_schema) || '.' || quote_ident(p_table);
selquery := selquery || '(';
valquery := ' VALUES (';
FOR colrec IN SELECT table_schema, table_name, column_name, data_type
FROM information_schema.columns
WHERE table_name = p_table and table_schema = p_schema
ORDER BY ordinal_position
LOOP
selquery := selquery || quote_ident(colrec.column_name) || ',';
selvalue :=
'SELECT CASE WHEN ' || quote_ident(colrec.column_name) || ' IS NULL' ||
' THEN ''NULL''' ||
' ELSE '''' || quote_literal('|| quote_ident(colrec.column_name) || ')::text || ''''' ||
' END' ||
' FROM '||quote_ident(p_schema)||'.'||quote_ident(p_table);
EXECUTE selvalue INTO colvalue;
valquery := valquery || colvalue || ',';
END LOOP;
-- Replace the last , with a )
selquery := substring(selquery,1,length(selquery)-1) || ')';
valquery := substring(valquery,1,length(valquery)-1) || ')';
selquery := selquery || valquery;
RETURN selquery;
END
$BODY$
LANGUAGE plpgsql VOLATILE;
このように呼び出されます:
SELECT distinct dv_util.gen_insert_statement('pg_temp_' || sess_id::text,'my_data')
from pg_stat_activity
where procpid = pg_backend_pid()
私はこれをインジェクション攻撃に対してテストしていません。quote_literal呼び出しがそれに対して十分でない場合はお知らせください。
また、単純に:: textにキャストして再び戻すことができる列に対してのみ機能します。
また、これはGreenplum用ですが、Postgres、CMIIWで動作しない理由は考えられません。