web-dev-qa-db-ja.com

PostgreSQLテーブルから特定の行をINSERT SQLスクリプトとしてエクスポートする

私は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を試しましたが、これを行うオプションが見つかりません。

150
null

エクスポートするセットでテーブルを作成し、コマンドラインユーティリティ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はスキーマをダンプしません。

以下にコメントするように、テーブルの代わりにビューを作成すると、新しいエクスポートが必要なときにテーブルを作成する必要がなくなります。

236
Clodoaldo Neto

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_dumppsqlなどのクライアントプログラムとは異なります 。両方が同じマシンで実行されている場合、それは重要ではありませんが、リモート接続では実行されます。

Psqlの \copyコマンド もあります:

フロントエンド(クライアント)コピーを実行します。これはSQL COPYコマンドを実行する操作ですが、サーバーが指定されたファイルを読み書きする代わりに、psqlはファイルを読み書きし、サーバーとローカルファイルシステム間でデータをルーティングします。これは、ファイルのアクセス可能性と特権がサーバーではなくローカルユーザーのものであり、SQLスーパーユーザー特権が必要ないことを意味します。

149

これは簡単で高速pgAdminを使用してテーブルをスクリプトにエクスポート手動で追加インストールなしでにする方法です。

  1. ターゲットテーブルを右クリックして、「バックアップ」を選択します。
  2. バックアップを保存するファイルパスを選択します。フォーマットとして「プレーン」を選択します。
  3. 下部にある[ダンプオプション#2]タブを開き、[列の挿入を使用]をオンにします。
  4. [バックアップ]ボタンをクリックします。
  5. 結果のファイルをテキストリーダー(notepad ++など)で開くと、テーブル全体を作成するスクリプトが取得されます。そこから、生成されたINSERTステートメントを単純にコピーできます。

このメソッドは、@ Clodoaldo Netoの回答で示されているように、export_tableを作成する手法とも連携します。

Click right on target table and choose "Backup"

Choose a destination path and change the format to "Plain"

Open the tab "Dump Options #2" at the bottom and check "Use Column Inserts"

You can copy the INSERT Statements from there.

21
Andi R

SQL Workbench にはそのような機能があります。

クエリを実行した後、クエリ結果を右クリックし、「SQLとしてデータをコピー> SQL挿入」を選択します

9
machinery

私のユースケースでは、単純にgrepにパイプすることができました。

pg_dump -U user_name --data-only --column-inserts -t nyummy.cimory | grep "tokyo" > tokyo.sql
6
M.Vanderlee

@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に相当するものを見つけました。

2
Vi Shen

特定のレコードでテーブルを表示してから、sqlファイルをダンプできます

CREATE VIEW foo AS
SELECT id,name,city FROM nyummy.cimory WHERE city = 'tokyo'
2

これを行うための簡単な手順をノックアップしました。それは単一の行に対してのみ機能するため、必要な行を選択するだけの一時ビューを作成し、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で動作しない理由は考えられません。

0
PhilHibbs