Wyeksportuj określone wiersze z tabeli PostgreSQL jako skrypt SQL INSERT

196

Mam schemat bazy danych o nazwie: nyummyi tabelę o nazwie 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)
);

Chcę wyeksportować dane cimorytabeli jako wstawianie pliku skryptu SQL. Chcę jednak eksportować rekordy / dane tylko wtedy, gdy miasto jest równe „tokyo” (zakładając, że wszystkie dane miasta są pisane małymi literami).

Jak to zrobić?

Nie ma znaczenia, czy rozwiązanie jest dostępne w darmowych narzędziach GUI, czy w wierszu poleceń (chociaż rozwiązanie narzędzi GUI jest lepsze). Próbowałem pgAdmin III, ale nie mogę znaleźć opcji, aby to zrobić.

zero
źródło
2
możesz pominąć instrukcje INSERT i po prostu skopiować za pomocą SELECT bezpośrednio między bazami danych. albertech.blogspot.com/2016/11/…
jar
PostgreSQL nie może wybierać między bazami danych. Przynajmniej starsze wersje nie mogą, podobnie jak Greenplum, nie wiem o 9.x.
PhilHibbs
Zdaję sobie sprawę, to jest stary, ale chciałem tylko wspomnieć, że to jest możliwe wybranie całej baz danych wykorzystujących dblink , która jest dostępna od co najmniej V8.3. Wykorzystuje zagraniczne serwery i owijarki danych obcych do łączenia się ze „zdalnymi” bazami danych. Działa to niezależnie od tego, czy te bazy danych istnieją w tej samej instancji, czy w zupełnie innych hostach. Użyłem go dość szeroko, aby stworzyć zmaterializowane widoki do innych baz danych, aby ułatwić pewne raportowanie i takie i działa świetnie.
G_Hosa_Phat

Odpowiedzi:

280

Utwórz tabelę z zestawem, który chcesz wyeksportować, a następnie użyj narzędzia wiersza polecenia pg_dump, aby wyeksportować do pliku:

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 zrzuci jako polecenia wstawiania z nazwami kolumn.

--data-only nie zrzucaj schematu.

Jak skomentowano poniżej, utworzenie widoku zamiast tabeli pozwoli na uniknięcie tworzenia tabeli, ilekroć konieczny jest nowy eksport.

Clodoaldo Neto
źródło
3
W porządku, na razie twoje rozwiązanie działa. Jedną z rzeczy, których mi brakuje, jest dodanie „-U nazwa_użytkownika”. Prawie mi się też udaje z narzędziem ToraSQL, po prostu ma błąd w danych daty i czasu w wyniku skryptu. Jeśli żadne nie da rozwiązania GUI w ciągu 2 dni, twoja odpowiedź zostanie zaakceptowana
null
2
Po prostu chcesz udostępnić innym osobom, możesz również skorzystać z tego darmowego narzędzia GUI: SQL Workbench / J (ze sterownikiem postgreSQL jdbc4), aby zrobić to samo.
null
1
Byłoby to znacznie lepsze create view export_view..., ponieważ widok byłby aktualny wraz ze zmianami w tabeli podstawowej. W docs powiedzieć, --table=table: Dump only tables (or **views**...więc miałem nadzieję to będzie działać, ale dumping widok niestety daje żadnych danych. : P
najlepiej
@poshest Działa dla mnie w wersji 9.5. Co dokładnie próbowałeś?
Clodoaldo Neto,
@ClodoaldoNeto och, OK świetnie! Mam nadzieję, że uda mi się to uruchomić. Użyłem pg_dump --table=my_schema.my_view --data-only --inserts my_db > data.sqlwersji 9.5.3, a moje createoświadczenie było takie samo, jak twoje create view.... W wyniku otrzymuję tylko zwykłe komentarze i SETinstrukcje pg_dump . Nie jestem pewien, gdzie się mylę.
najdalej
176

Przez eksport danych tylko do użytku COPY.
Otrzymujesz plik z jednym wierszem tabeli w wierszu jako zwykły tekst (nie INSERTpolecenia), jest mniejszy i szybszy:

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

Zaimportuj to samo do innej tabeli o tej samej strukturze w dowolnym miejscu za pomocą:

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

COPYzapisuje i odczytuje pliki lokalne na serwerze , w przeciwieństwie do programów klienckich takich jak pg_dumplub, psqlktóre odczytują i zapisują pliki lokalne na kliencie . Jeśli oba działają na tym samym komputerze, nie ma to większego znaczenia, ale dotyczy zdalnych połączeń.

Istnieje również \copypolecenie psql, które:

Wykonuje kopię nakładki (klienta). Jest to operacja, która uruchamia COPYpolecenie SQL , ale zamiast serwera odczytującego lub zapisującego określony plik, psql czyta lub zapisuje plik i kieruje dane między serwerem a lokalnym systemem plików. Oznacza to, że dostęp do plików i uprawnienia należą do lokalnego użytkownika, a nie do serwera, i nie są wymagane żadne uprawnienia administratora SQL.

Erwin Brandstetter
źródło
10
OP wzywa konkretnie do danych jako wstawienia pliku skryptu sql . Myślę, że on mówi o insertpoleceniach, prawda?
Clodoaldo Neto,
1
@Clodoaldo: Możesz mieć rację, w takim przypadku Twoja odpowiedź byłaby lepsza. Można również skopiować skrypt CREATE do pgAdmin osobno (tak jak OP wspomina o GUI).
Erwin Brandstetter,
3
STDINi STDOUTmoże być używany zamiast ścieżki pliku, przydatny w przypadku eksportu małych danych.
Amir Ali Akbari
1
Bez tej --column-insertsflagi, pg_dump używa COPYod standardowego wejścia dla każdej z tabel w kodzie SQL generuje.
Randall
2
Uważaj, aby kolejność kolumn, które wybierasz była zgodna z kolejnością kolumn w docelowej bazie danych. Jeśli nie, może to zakończyć się niepowodzeniem lub, co gorsza, sukcesem, ale wstaw złe dane.
Nathan Wallace
32

Jest to łatwy i szybki sposób ręcznego eksportowania tabeli do skryptu za pomocą pgAdmin bez dodatkowych instalacji :

  1. Kliknij prawym przyciskiem myszy tabelę docelową i wybierz „Kopia zapasowa”.
  2. Wybierz ścieżkę pliku do zapisania kopii zapasowej. Jako Format wybierz „Zwykły”.
  3. Otwórz zakładkę „Opcje zrzutu 2” u dołu i zaznacz „Użyj wstawek kolumn”.
  4. Kliknij przycisk Kopia zapasowa.
  5. Jeśli otworzysz plik wynikowy za pomocą czytnika tekstu (np. Notepad ++), otrzymasz skrypt do utworzenia całej tabeli. Stamtąd możesz po prostu skopiować wygenerowane instrukcje INSERT.

Ta metoda działa również z techniką tworzenia tabeli eksportu, jak pokazano w odpowiedzi @Clodoaldo Neto.

Kliknij prawym przyciskiem myszy tabelę docelową i wybierz „Kopia zapasowa”

Wybierz ścieżkę docelową i zmień format na „Zwykły”

Otwórz zakładkę „Opcje zrzutu 2” u dołu i zaznacz „Użyj wstawek kolumn”

Stamtąd możesz skopiować wyciągi INSERT.

Andi R.
źródło
Kiedy to robię, nie ma opcji „Bakckup”. Jest to pgAdmin III v1.18.1 łączący się z Greenplum 4.3.4.1 (w oparciu o PostgreSQL 8.2.15).
PhilHibbs
Zainstalowałem pgAdmin III v1.18.1 i była opcja „backup”. Podłączyłem się do PostgreSQL 9.5. Problem najprawdopodobniej występuje między pgAdmin a Greenplum.
Andi R
Działa zgodnie z przeznaczeniem w pgAdmin4
Nikhil
9

SQL Workbench ma taką funkcję.

Po uruchomieniu zapytania kliknij prawym przyciskiem myszy wyniki zapytania i wybierz „Kopiuj dane jako SQL> Wstaw SQL”

maszyneria
źródło
1
Działa świetnie. Jeśli wybierzesz „postgres” jako „sterownik”, prawdopodobne jest, że będziesz musiał pobrać sterowniki JDBC samodzielnie: jdbc.postgresql.org/download.html (jest to plik .jar - plik binarny java) i dodać go jako „sterownik” połączenia postgresql. Łańcuch połączenia (lub adres URL jak w interfejsie) powinien wyglądać tak: jdbc: postgresql: //127.0.0.1: 5432 / db_name
mrmuggles
DBVisualizer ma podobną i doskonałą funkcję, którą można skopiować do pliku lub bezpośrednio do schowka.
Noumenon,
8

W moim przypadku użycia byłem w stanie po prostu potokować do grep.

pg_dump -U user_name --data-only --column-inserts -t nyummy.cimory | grep "tokyo" > tokyo.sql
M.Vanderlee
źródło
2
Trzeba rozważyć możliwość posiadania „tokyo” w innej dziedzinie.
Buyut Joko Rivai,
@BuyutJokoRivai, ponieważ w większości przypadków jest to zrzut tabeli, w większości przypadków powinno być w porządku
Ismail Iqbal
Najbardziej sprytny sposób spośród innych w sprawie <3
Nam G VU
Chociaż z dużym stołem zrzucisz wszystkie wiersze dla grep, który jest przypadkiem pułapki dla twojego rozwiązania. Następnie bardziej odpowiedni jest sposób, w jaki wyszukujemy i przechowujemy wyniki do tabeli w celu zrzucenia, ponieważ tutaj stackoverflow.com/a/12816187/248616 jest bardziej odpowiedni
Nam G VU
5

Próbowałem napisać procedurę w ten sposób, opartą na kodach @PhilHibbs, w inny sposób. Proszę spojrzeć i przetestować.

 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;

I wtedy :

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

testowany na moim postgresie 9.1, z tabelą z mieszanym typem pola danych (tekst, double, int, znacznik czasu bez strefy czasowej itp.).

Dlatego potrzebny jest CAST w typie TEXT. Mój test działa poprawnie dla około 9 milionów linii, wygląda na to, że zawiedzie tuż przed 18 minutami pracy.

ps: Znalazłem odpowiednik mysql w sieci.

Vi Shen
źródło
3

Możesz zrobić widok tabeli z określonymi rekordami, a następnie zrzucić plik sql

CREATE VIEW foo AS
SELECT id,name,city FROM nyummy.cimory WHERE city = 'tokyo'
Giorgi Peikrishvili
źródło
3
Próbowałem w pgAdmin III, ale w przypadku obiektu View nie ma opcji zrzutu.
null
Wypróbuj navicat. Używam go i ma opcję eksportu skryptu sql
Giorgi Peikrishvili 10.10
@Giorgi: czy jest dostępna wersja freeware?
null
Nie jest możliwe korzystanie z Postgres 9.1
HCarrasko
2

Właśnie podjąłem szybką procedurę, aby to zrobić. Działa tylko dla jednego wiersza, dlatego tworzę widok tymczasowy, który po prostu wybiera wiersz, który chcę, a następnie zastępuję pg_temp.temp_view rzeczywistą tabelą, do której chcę wstawić.

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;

Wywołano w ten sposób:

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

Nie testowałem tego pod kątem ataków z iniekcją, daj mi znać, jeśli wywołanie quote_literal nie jest wystarczające.

Działa to również tylko w przypadku kolumn, które można po prostu rzutować na :: text iz powrotem.

Dotyczy to również Greenplum, ale nie mogę wymyślić powodu, dla którego nie działałoby to na Postgres, CMIIW.

PhilHibbs
źródło
-2

próbowałem w pgadmin wykonywania zapytania z " EXECUTE QUERY WRITE RESULT TO FILE " opcją

to tylko eksport danych, w przeciwnym razie spróbuj

pg_dump -t view_name DB_name > db.sql

-t opcja używana dla ==> Zrzuć tylko tabele (lub widoki lub sekwencje) pasujące do tabeli, patrz

solaimuruganv
źródło
1
Spowoduje to jedynie wyeksportowanie create viewwyciągu
cdmckay