Exporter des lignes spécifiques d'une table PostgreSQL en tant que script INSERT SQL

196

J'ai un schéma de base de données nommé: nyummyet une table nommée 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)
);

Je souhaite exporter les cimorydonnées de la table en tant que fichier de script SQL d'insertion. Cependant, je souhaite uniquement exporter les enregistrements / données où la ville est égale à «tokyo» (en supposant que les données de la ville sont toutes en minuscules).

Comment faire?

Peu importe que la solution soit dans des outils GUI gratuits ou en ligne de commande (bien que la solution d'outils GUI soit meilleure). J'avais essayé pgAdmin III, mais je ne trouve pas d'option pour le faire.

nul
la source
2
vous pouvez ignorer les instructions INSERT et simplement copier à l'aide de SELECT directement entre les bases de données. albertech.blogspot.com/2016/11/…
pot
PostgreSQL ne peut pas sélectionner parmi les bases de données. Au moins, les anciennes versions ne le peuvent pas et Greenplum non plus, je ne sais pas pour 9.x.
PhilHibbs
Je me rends compte que c'est vieux, mais je voulais juste mentionner qu'il est possible de sélectionner parmi les bases de données en utilisant dblink , qui est disponible depuis au moins la v8.3. Il utilise des serveurs étrangers et des wrappers de données étrangers pour se connecter à des bases de données "distantes". Cela fonctionne que ces bases de données existent sur la même instance ou sur des hôtes entièrement différents. Je l'ai utilisé assez largement pour créer des vues matérialisées dans d'autres bases de données pour faciliter certains rapports et ainsi de suite et cela fonctionne très bien.
G_Hosa_Phat

Réponses:

282

Créez une table avec l'ensemble que vous souhaitez exporter, puis utilisez l'utilitaire de ligne de commande pg_dump pour exporter vers un fichier:

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 videra sous forme de commandes d'insertion avec des noms de colonne.

--data-only ne videz pas le schéma.

Comme indiqué ci-dessous, la création d'une vue dans au lieu d'une table évitera la création de table chaque fois qu'une nouvelle exportation est nécessaire.

Clodoaldo Neto
la source
3
D'accord, jusqu'à présent, votre solution fonctionne. Une chose manquée est que je dois ajouter "-U nom_utilisateur". J'ai aussi presque réussi avec l'outil ToraSQL, c'est juste qu'il a une erreur dans les données date-heure dans le résultat du script. Si personne ne peut donner de solution d'outil graphique en 2 jours, votre réponse sera acceptée
null
2
Je veux juste partager avec d'autres personnes, vous pouvez également utiliser cet outil graphique gratuit: SQL Workbench / J (avec le pilote jgreb4 postgreSQL), pour faire la même chose.
null
2
Ce serait beaucoup mieux avec create view export_view..., car la vue resterait à jour avec les modifications apportées à la table de base. Les docs disent --table=table: Dump only tables (or **views**...que j'avais donc un peu d'espoir que cela fonctionnerait, mais le dumping d'une vue ne donne malheureusement aucune donnée. : P
poshest
1
@poshest Cela fonctionne pour moi en 9.5. Qu'avez-vous essayé exactement?
Clodoaldo Neto
@ClodoaldoNeto oh, OK super! J'espère que je peux aussi le faire fonctionner. J'ai utilisé la pg_dump --table=my_schema.my_view --data-only --inserts my_db > data.sqlversion 9.5.3 et ma createdéclaration était la même que la vôtre sauf create view.... Tout ce que j'obtiens dans la sortie est les commentaires et les SETdéclarations habituels de pg_dump . Je ne sais pas où je vais mal.
Poshest
176

Pour une exportation que les données utilisation COPY.
Vous obtenez un fichier avec une ligne de tableau par ligne en texte brut (pas de INSERTcommandes), il est plus petit et plus rapide:

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

Importez le même dans une autre table de la même structure n'importe où avec:

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

COPYécrit et lit des fichiers locaux sur le serveur , contrairement aux programmes clients comme pg_dumpou psqlqui lisent et écrivent des fichiers locaux sur le client . Si les deux s'exécutent sur la même machine, cela n'a pas beaucoup d'importance, mais c'est le cas pour les connexions à distance.

Il y a aussi la \copycommande de psql qui:

Effectue une copie frontale (client). Il s'agit d'une opération qui exécute une COPYcommande SQL , mais au lieu que le serveur lise ou écrive le fichier spécifié, psql lit ou écrit le fichier et achemine les données entre le serveur et le système de fichiers local. Cela signifie que l'accessibilité et les privilèges des fichiers sont ceux de l'utilisateur local et non du serveur et qu'aucun privilège de superutilisateur SQL n'est requis.

Erwin Brandstetter
la source
10
L'OP appelle spécifiquement les données en tant que fichier de script sql d'insertion . Je suppose qu'il parle de insertcommandes, n'est-ce pas?
Clodoaldo Neto
1
@Clodoaldo: Vous avez peut-être raison, auquel cas votre réponse serait mieux adaptée. On pourrait également copier le script CREATE dans pgAdmin séparément (comme l'OP mentionne les interfaces graphiques).
Erwin Brandstetter
3
STDINet STDOUTpeut être utilisé à la place du chemin de fichier, utile pour les petites exportations de données.
Amir Ali Akbari
1
Sans l' --column-insertsindicateur, pg_dump utilise un COPYde STDIN pour chacune des tables dans le code SQL qu'il génère.
Randall
2
Veillez à ce que l'ordre des colonnes que vous SÉLECTIONNEZ corresponde à l'ordre des colonnes dans la base de données de destination. Si ce n'est pas le cas, cela pourrait échouer, ou pire, réussir, mais insérer des données incorrectes.
Nathan Wallace
32

C'est un moyen facile et rapide d' exporter une table vers un script avec pgAdmin manuellement sans installations supplémentaires :

  1. Faites un clic droit sur la table cible et sélectionnez "Sauvegarde".
  2. Sélectionnez un chemin de fichier pour stocker la sauvegarde. Comme Format, choisissez "Normal".
  3. Ouvrez l'onglet "Dump Options # 2" en bas et cochez "Use Column Inserts".
  4. Cliquez sur le bouton Sauvegarder.
  5. Si vous ouvrez le fichier résultant avec un lecteur de texte (par exemple notepad ++), vous obtenez un script pour créer la table entière. De là, vous pouvez simplement copier les instructions INSERT générées.

Cette méthode fonctionne également avec la technique de création d'un export_table comme démontré dans la réponse de @Clodoaldo Neto.

Cliquez à droite sur la table cible et choisissez "Sauvegarde"

Choisissez un chemin de destination et changez le format en "Normal"

Ouvrez l'onglet "Dump Options # 2" en bas et cochez "Use Column Inserts"

Vous pouvez copier les instructions INSERT à partir de là.

Andi R
la source
Lorsque je fais cela, il n'y a pas d'option "Bakckup". Il s'agit de pgAdmin III v1.18.1 se connectant à Greenplum 4.3.4.1 (basé sur PostgreSQL 8.2.15).
PhilHibbs
J'ai installé pgAdmin III v1.18.1 et il y avait l'option "sauvegarde". Je me suis connecté à un PostgreSQL 9.5. Le problème se situe donc très probablement entre pgAdmin et Greenplum.
Andi R
Fonctionne comme prévu dans pgAdmin4
Nikhil
9

SQL Workbench possède une telle fonctionnalité.

Après avoir exécuté une requête, faites un clic droit sur les résultats de la requête et choisissez "Copier les données en tant que SQL> Insertion SQL"

machinerie
la source
1
Cela fonctionne très bien. Lorsque vous choisissez «postgres» comme «pilote», il est probable que vous devrez télécharger les pilotes JDBC vous-même: jdbc.postgresql.org/download.html (c'est un fichier .jar - binaire java) et l'ajouter en tant que «conducteur» de la connexion postgresql. La chaîne de connexion (ou l'URL comme dans l'interface) devrait ressembler à ceci: jdbc: postgresql: //127.0.0.1: 5432 / db_name
mrmuggles
DBVisualizer a une fonctionnalité similaire et excellente qui peut copier dans un fichier ou directement dans le presse-papiers.
Noumenon
8

Pour mon cas d'utilisation, j'ai pu simplement diriger vers grep.

pg_dump -U user_name --data-only --column-inserts -t nyummy.cimory | grep "tokyo" > tokyo.sql
M.Vanderlee
la source
2
Il faut penser à avoir «tokyo» dans un autre domaine.
Buyut Joko Rivai
@BuyutJokoRivai puisqu'il s'agit d'un vidage de table uniquement dans la plupart des cas, cela devrait aller
Ismail Iqbal
Le moyen le plus intelligent parmi les autres sur l'affaire <3
Nam G VU
Bien qu'avec une grande table, vous viderez toutes les lignes pour le grep qui est le casse-tête de votre solution. Ensuite, la façon dont nous interrogeons et stockons le résultat dans une table à vider comme ici stackoverflow.com/a/12816187/248616 est plus appropriée
Nam G VU
5

J'ai essayé d'écrire une procédure faisant cela, basée sur les codes @PhilHibbs, d'une manière différente. Veuillez jeter un œil et tester.

 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;

Puis :

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

testé sur mon postgres 9.1, avec une table avec type de données à champs mixtes (texte, double, int, horodatage sans fuseau horaire, etc.).

C'est pourquoi le CAST en type TEXT est nécessaire. Mon test fonctionne correctement pour environ 9 millions de lignes, il semble qu'il échoue juste avant 18 minutes de fonctionnement.

ps: J'ai trouvé un équivalent pour mysql sur le WEB.

Vi Shen
la source
3

Vous pouvez afficher la table avec des enregistrements spécifiques, puis vider le fichier sql

CREATE VIEW foo AS
SELECT id,name,city FROM nyummy.cimory WHERE city = 'tokyo'
Giorgi Peikrishvili
la source
3
Je l'ai essayé dans pgAdmin III, mais pour l'objet View, il n'y a pas d'option pour le dumping.
null
Essayez navicat. Je l'utilise et il a l'option d'exportation de script sql
Giorgi Peikrishvili
@Giorgi: existe-t-il une version freeware?
null
Il n'est pas possible d'utiliser Postgres 9.1
HCarrasko le
2

Je viens de lancer une procédure rapide pour ce faire. Cela ne fonctionne que pour une seule ligne, donc je crée une vue temporaire qui sélectionne simplement la ligne que je veux, puis je remplace pg_temp.temp_view par la table réelle dans laquelle je veux insérer.

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;

Appelé ainsi:

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

Je n'ai pas testé cela contre les attaques par injection, veuillez me faire savoir si l'appel quote_literal n'est pas suffisant pour cela.

De plus, cela ne fonctionne que pour les colonnes qui peuvent être simplement converties en :: text et inversement.

C'est aussi pour Greenplum mais je ne peux pas penser à une raison pour laquelle cela ne fonctionnerait pas sur Postgres, CMIIW.

PhilHibbs
la source
-2

avez-vous essayé dans pgadmin l'exécution de la requête avec " EXECUTE QUERY WRITE RESULT TO FILE " option

sa seule exportation des données, sinon essayez comme

pg_dump -t view_name DB_name > db.sql

-t option utilisée pour ==> Vider uniquement les tables (ou vues ou séquences) correspondant à la table, voir

solaimuruganv
la source
1
Cela n'exportera qu'une create viewdéclaration
cdmckay