Ekspor baris tertentu dari tabel PostgreSQL sebagai skrip INSERT SQL

196

Saya memiliki skema database bernama: nyummydan tabel bernama 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)
);

Saya ingin mengekspor data cimorytabel sebagai menyisipkan file skrip SQL. Namun, saya hanya ingin mengekspor catatan / data di mana kota itu sama dengan 'tokyo' (anggap data kota semuanya huruf kecil).

Bagaimana cara melakukannya?

Tidak masalah apakah solusinya ada di alat GUI freeware atau baris perintah (meskipun solusi alat GUI lebih baik). Saya telah mencoba pgAdmin III, tetapi saya tidak dapat menemukan opsi untuk melakukan ini.

batal
sumber
2
Anda bisa melewatkan pernyataan INSERT dan cukup menyalin menggunakan SELECT langsung antara database. albertech.blogspot.com/2016/11/...
jar
PostgreSQL tidak dapat memilih di seluruh basis data. Setidaknya, versi yang lebih lama tidak bisa dan Greenplum juga tidak, tidak tahu tentang 9.x.
PhilHibbs
Saya menyadari ini sudah tua, tapi aku hanya ingin menyebutkan bahwa itu adalah mungkin untuk memilih di database menggunakan dblink , yang telah tersedia setidaknya sejak V8.3. Itu menggunakan server asing dan pembungkus data asing untuk terhubung ke "remote" database. Ini berfungsi baik jika basis data itu ada pada contoh yang sama atau host yang sama sekali berbeda. Saya telah menggunakannya cukup luas untuk membuat pandangan terwujud ke dalam database lain untuk memfasilitasi pelaporan tertentu dan itu dan itu bekerja dengan baik.
G_Hosa_Phat

Jawaban:

282

Buat tabel dengan set yang ingin Anda ekspor dan kemudian gunakan utilitas baris perintah pg_dump untuk mengekspor ke file:

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 akan membuang sebagai menyisipkan perintah dengan nama kolom.

--data-only jangan buang skema.

Seperti yang dikomentari di bawah ini, membuat tampilan bukan tabel akan meniadakan pembuatan tabel setiap kali ekspor baru diperlukan.

Clodoaldo Neto
sumber
3
Baiklah, sejauh ini solusi Anda bekerja. Satu hal yang terlewatkan adalah saya perlu menambahkan "-U user_name". Saya juga hampir berhasil dengan alat ToraSQL, hanya saja ia memiliki kesalahan dalam data waktu-waktu dalam hasil skrip. Jika tidak ada yang bisa memberikan solusi alat GUI dalam 2 hari, jawaban Anda akan diterima
null
2
Hanya ingin berbagi dengan orang lain, Anda juga dapat menggunakan alat GUI gratis ini: SQL Workbench / J (dengan driver jdbc4 postgreSQL), untuk melakukan hal yang sama.
null
2
Ini akan jauh lebih baik dengan create view export_view..., karena tampilan akan tetap up-to-date dengan perubahan pada tabel dasar. The docs mengatakan --table=table: Dump only tables (or **views**...jadi aku punya beberapa harapan ini akan bekerja, tetapi membuang pandangan sedih menghasilkan data tidak. : P
poshest
1
@poshest Ini bekerja untuk saya di 9.5. Apa sebenarnya yang Anda coba?
Clodoaldo Neto
@ClodoaldoNeto oh, OK bagus! Saya harap saya juga bisa membuatnya bekerja. Saya menggunakan pg_dump --table=my_schema.my_view --data-only --inserts my_db > data.sql, versi 9.5.3, dan createpernyataan saya sama dengan Anda kecuali create view.... Yang saya dapatkan di output adalah komentar dan SETpernyataan pg_dump yang biasa . Tidak yakin di mana saya salah.
poshest
176

Untuk penggunaan ekspor data sajaCOPY .
Anda mendapatkan file dengan satu baris tabel per baris sebagai teks biasa (bukan INSERTperintah), lebih kecil dan lebih cepat:

COPY (SELECT * FROM nyummy.cimory WHERE city = 'tokio') TO '/path/to/file.csv';

Impor yang sama ke tabel lain dari struktur yang sama di mana saja dengan:

COPY other_tbl FROM '/path/to/file.csv';

COPYmenulis dan membaca file secara lokal ke server , tidak seperti program klien seperti pg_dumpatau psqlyang membaca dan menulis file secara lokal ke klien . Jika keduanya berjalan pada mesin yang sama, tidak masalah, tetapi itu berlaku untuk koneksi jarak jauh.

Ada juga \copyperintah psql yang:

Melakukan salinan frontend (klien). Ini adalah operasi yang menjalankan COPYperintah SQL , tetapi alih-alih server membaca atau menulis file yang ditentukan, psql membaca atau menulis file dan merutekan data antara server dan sistem file lokal. Ini berarti bahwa aksesibilitas file dan hak istimewa adalah milik pengguna lokal, bukan server, dan tidak ada hak istimewa pengguna super SQL.

Erwin Brandstetter
sumber
10
OP panggilan khusus untuk data sebagai memasukkan file skrip sql . Saya kira dia berbicara tentang insertperintah, bukan?
Clodoaldo Neto
1
@Clodoaldo: Anda mungkin benar, dalam hal ini jawaban Anda akan lebih cocok. Anda juga dapat menyalin skrip CREATE di pgAdmin secara terpisah (sebagaimana OP menyebutkan GUI).
Erwin Brandstetter
3
STDINdan STDOUTdapat digunakan sebagai ganti path file, berguna untuk ekspor data kecil.
Amir Ali Akbari
1
Tanpa itu --column-insertsbendera, pg_dump menggunakan COPYdari STDIN untuk masing-masing tabel dalam kode SQL yang dihasilkannya.
Randall
2
Berhati-hatilah bahwa urutan kolom yang Anda PILIH cocok dengan urutan kolom dalam basis data tujuan. Jika tidak, ini bisa gagal, atau lebih buruk, berhasil tetapi memasukkan data buruk.
Nathan Wallace
32

Ini adalah cara mudah dan cepat untuk mengekspor tabel ke skrip dengan pgAdmin secara manual tanpa instalasi tambahan :

  1. Klik kanan pada tabel target dan pilih "Backup".
  2. Pilih jalur file untuk menyimpan cadangan. Sebagai Format pilih "Plain".
  3. Buka tab "Opsi Dump # 2" di bagian bawah dan centang "Gunakan Sisipan Kolom".
  4. Klik tombol Cadangan.
  5. Jika Anda membuka file yang dihasilkan dengan pembaca teks (mis. Notepad ++) Anda mendapatkan skrip untuk membuat seluruh tabel. Dari sana Anda cukup menyalin Pernyataan-INSERT yang dihasilkan.

Metode ini juga bekerja dengan teknik membuat export_table seperti yang ditunjukkan dalam jawaban @Clodoaldo Neto.

Klik kanan pada tabel target dan pilih "Cadangan"

Pilih jalur tujuan dan ubah format menjadi "Biasa"

Buka tab "Opsi Dump # 2" di bagian bawah dan centang "Gunakan Sisipan Kolom"

Anda dapat menyalin Pernyataan INSERT dari sana.

Andi R
sumber
Ketika saya melakukan ini, tidak ada opsi "Bakckup". Ini adalah pgAdmin III v1.18.1 yang terhubung ke Greenplum 4.3.4.1 (berdasarkan PostgreSQL 8.2.15).
PhilHibbs
Saya telah menginstal pgAdmin III v1.18.1 dan ada adalah yang "cadangan" pilihan. Saya terhubung ke PostgreSQL 9.5. Jadi masalahnya paling mungkin antara pgAdmin dan Greenplum.
Andi R
Bekerja sebagaimana dimaksud dalam pgAdmin4
Nikhil
9

SQL Workbench memiliki fitur seperti itu.

Setelah menjalankan kueri, klik kanan pada hasil kueri dan pilih "Salin Data Sebagai SQL> Sisipan SQL"

mesin
sumber
1
Ini bekerja dengan baik. Ketika Anda memilih 'postgres' sebagai 'driver', besar kemungkinan Anda harus mengunduh sendiri driver JDBC: jdbc.postgresql.org/download.html (ini adalah file .jar - java binary) dan menambahkannya sebagai 'driver' dari koneksi postgresql. String koneksi (atau URL seperti pada antarmuka) akan terlihat seperti itu: jdbc: postgresql: //127.0.0.1: 5432 / db_name
mrmuggles
DBVisualizer memiliki fitur serupa dan luar biasa yang dapat menyalin ke file atau langsung ke clipboard.
Noumenon
8

Untuk case-use saya, saya bisa hanya pipa untuk grep.

pg_dump -U user_name --data-only --column-inserts -t nyummy.cimory | grep "tokyo" > tokyo.sql
M.Vanderlee
sumber
2
Orang harus mempertimbangkan tentang memiliki 'tokyo' di bidang lain.
Buyut Joko Rivai
@BuyutJokoRivai karena ini adalah meja yang hanya membuang sebagian besar kasus, seharusnya tidak masalah
Ismail Iqbal
Cara paling pintar di antara yang lain dalam kasus ini <3
Nam G VU
Meskipun dengan meja besar, Anda akan membuang semua baris untuk grep yang merupakan kasus perangkap untuk solusi Anda. Kemudian, cara kami meminta dan menyimpan hasil ke tabel untuk dibuang seperti di sini stackoverflow.com/a/12816187/248616 lebih sesuai
Nam G VU
5

Saya mencoba menulis prosedur melakukan itu, berdasarkan pada kode @ PhilHibbs, dengan cara yang berbeda. Silakan lihat dan uji.

 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;

Lalu :

-- for a range
SELECT dump('public', 'my_table','my_id between 123456 and 123459'); 
-- for the entire table
SELECT dump('public', 'my_table','true');

diuji pada postgres 9.1 saya, dengan tabel dengan tipe data bidang campuran (teks, dobel, int, cap waktu tanpa zona waktu, dll).

Itu sebabnya CAST dalam jenis TEXT diperlukan. Tes saya berjalan dengan benar selama sekitar 9M baris, sepertinya gagal sebelum 18 menit berjalan.

ps: Saya menemukan padanan untuk mysql di WEB.

Vi Shen
sumber
3

Anda bisa membuat tampilan tabel dengan catatan tertentu dan kemudian membuang file sql

CREATE VIEW foo AS
SELECT id,name,city FROM nyummy.cimory WHERE city = 'tokyo'
Giorgi Peikrishvili
sumber
3
Saya mencobanya di pgAdmin III, tetapi untuk objek View, tidak ada opsi untuk dumping.
null
Coba navicat. Saya menggunakannya dan memiliki opsi skrip ekspor sql
Giorgi Peikrishvili
@Iorgi: apakah ada versi freeware?
null
Tidak mungkin menggunakan Postgres 9.1
HCarrasko
2

Saya baru saja mengetuk prosedur cepat untuk melakukan ini. Ini hanya berfungsi untuk satu baris, jadi saya membuat tampilan sementara yang hanya memilih baris yang saya inginkan, dan kemudian mengganti pg_temp.temp_view dengan tabel aktual yang ingin saya masukkan.

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;

Disebut demikian:

SELECT distinct dv_util.gen_insert_statement('pg_temp_' || sess_id::text,'my_data') 
from pg_stat_activity 
where procpid = pg_backend_pid()

Saya belum menguji ini terhadap serangan injeksi, beri tahu saya jika panggilan quote_literal tidak cukup untuk itu.

Juga hanya berfungsi untuk kolom yang dapat dengan mudah dilemparkan ke :: teks dan kembali lagi.

Ini juga untuk Greenplum tapi saya tidak bisa memikirkan alasan mengapa itu tidak bisa digunakan pada Postgres, CMIIW.

PhilHibbs
sumber
-2

sudahkah kamu mencoba di pgadmin mengeksekusi query dengan " EXECUTE QUERY WRITE RESULT TO FILE " opsi

itu hanya mengekspor data, coba yang lain suka

pg_dump -t view_name DB_name > db.sql

Opsi -t digunakan untuk ==> Tabel pencocokan hanya Dump (atau tampilan atau urutan) pencocokan, merujuk

solaimuruganv
sumber
1
Ini hanya akan mengekspor create viewpernyataan
cdmckay