Vous n'êtes pas identifié(e).
Pages : 1
Bonjour
J’aimerai dupliquer un enregistrement : seule la clef primaire, automatique (séquence), varie.
Pour cette requête, les DEFAULT proviendraient d'une requête.
Je voudrai quelque chose comme:
INSERT INTO table SELECT * //({les colonnes sans la clef qui elle doit être modifiée)
FROM table
WHERE id = {mon id à dupliquer}
Le nom des colonnes variant en fonctions du projet, je cherche une méthode globale sans la ressaisie des colonnes.
J’ai voulu créer une contrainte ou même règle mais je me suis perdu en route.
Est-il possible, en plus, que cette commande modifie la valeur de certaines colonnes ?
Merci d'avance
Olivier
Hors ligne
Oui, il suffit d'indiquer les valeurs qui varient. C'est d'ailleurs nécessaires car la clé primaire doit forcément changer. En supposant que votre champ de clé primaire s'appelle id, cela vous donnera quelque chose comme ça :
INSERT INTO table SELECT DEFAULT, <les autres champs avec modification si nécessaire> FROM table WHERE id=<l'id à dupliquer>;
Par exemple, pour une table à trois champs définie ainsi :
CREATE TABLE t1 (c1 serial primary key, c2 integer, c3 text);
Ça pourrait donner ceci :
INSERT INTO t1 SELECT DEFAULT, c2, c3 FROM t1 WHERE c1=10;
Guillaume.
Hors ligne
Ah gleu c'est malin, je n'y avais pas pensé . Par contre, il n'est pas possible de faire cela de manière générique, je suppose? (la demande d'Olivier précise qu'il voudrait ne pas saisir les colonnes).
Sinon, Olivier, je trouve cette demande très étrange. Je ne comprends pas quel sens cela peut avoir. Pourriez-vous nous l'expliquer, s'il vous plaît? Si l'on a deux enregistrements avec des clés différentes, la logique relationnelle veut justement que les lignes correspondent à des données différentes. Avoir 2 lignes de même données sauf la clé autogénérée, c'est ce que l'on cherche normalement à éviter.
Hors ligne
Bonjour
et de merci de cette réponse.
L'idée est là, mais cette insertion suppose qu'il faille saisir chaque colonne à modifier.
Je cherche quelque de plus générique, genre :
INSERT INTO table SELECT * FROM table WHERE id = '4'
NB : Je ne comprends bien ce que DEFAULT vient faire dans un SELECT.
Je ne connaisais pas l'expression
INSERT INTO table SELECT DEFAULT FROM table
J'ai cette erreur lorsque je l'utilise :
ERROR: syntax error at or near "DEFAULT"
req : SELECT DEFAULT FROM table.
Cordialement
Olivier
Hors ligne
Bonjour
Je n'avais vu le message intermédiaire.
Mon problème est que j’ai besoin de dupliquer des comptes clients complets : nous avons besoin de retrouver les mêmes informations d’un client sur deux comptes différents.
Les raisons :
+ Le client peut divorcer et nous demande la création d’un nouveau compte.
+ Il déménagement et une autre société prendra donc le suivi de ce nouveau client mais avec son historique.
En dupliquant, on éviterait la ressaisie.
Voilà, en espérant avoir été plus clair.
Cordialement
Olivier DUCTEIL
Hors ligne
DEFAULT indique qu'on veut la valeur par défaut de la colonne. Dans le cas d'une colonne serial, cela permet de récupérer la prochaine valeur de la séquence et évite ainsi la violation de contrainte.
Il n'existe pas de façon de faire l'insert que vous voulez sans indiquer la liste des colonnes. Si vous utilisez *, vous aurez toutes les colonnes sans possibilité de les modifier. Ça ne remplit déjà pas votre besoin mais si en plus vous avez une clé primaire, cette dernière empêchera l'insertion.
Pour le dire plus rapidement, il n'existe pas de moyen de faire ce que vous voulez sans indiquer la liste des colonnes.
Guillaume.
Hors ligne
Bonjour
C'est ce que je soupçonnais.
Merci quand même.
Cordialement
Olivier
Hors ligne
Bonjour,
Je poste mon message ici pour ne pas perdre la réponse faîte à Olivier, même si je suis à coté de la plaque.
Si Olivier avait posé la même question dans le cadre de la création d'un doublon automatique, ma réponse aurait été :
Bonjour Olivier,
Que ce soit avec des règles ou des triggers, tu as certainement rencontré le problème scolaire de la récursivité de ce traitement (INSERT => INSERT => INSERT).
Pour t'en sortir, tu peux simplement créer une vue qui sera utilisée plutôt que sa table pour les opérations SQL. Une règle sur cette vue te permettra alors d'implémenter l'effet désiré (et si tu veux modifier des colonnes bien sûr).
CREATE SEQUENCE seq
INCREMENT 1
MINVALUE 1;
CREATE TABLE test
(
id integer DEFAULT nextval('seq'),
col1 character varying,
col2 character varying
);
CREATE OR REPLACE VIEW "view" AS
SELECT test.id, test.col1, test.col2
FROM test;
CREATE OR REPLACE RULE test AS
ON INSERT TO view DO INSTEAD ( INSERT INTO test (col1, col2)
VALUES (new.col1, new.col2);
INSERT INTO test (col1, col2)
VALUES (new.col1, new.col2);
);
Si tu exécute
INSERT INTO "view" col1,col2 VALUES ('1','2');
puis
SELECT * from "view";
tu obtiens bien
id col1 col2
1 1 2
2 1 2
Tu peux aussi ajouter une règle pour la commande UPDATE, mais s'il faut alors modifier la ligne en doublon, cela va se corser !
Dans ce cas, et si tes règles de modification de colonne sont trop complexes, il s'agira de créer une fonction (plpgsql par exemple) qui sera appelée dans ta règle.
Mais bon, j'ai vu un peu trop loin, ça servira pour plus tard.
Bonne soirée,
Julien.
Hors ligne
Il est possible de parvenir a ses fins grace à 'DO' ( a partir de 9.0 ou sinon avec une fonction plpgsql avant).
Je suis un peu flemmard a cette heure, donc je n'écris pas le code, mais le principe est le suivant: DO permet de faire comme un fonction mais sans conserver le code.
Donc, dans le DO ou au pire dans une fonction plpgsql, faire:
* récupérer la liste des colonnes de la tables *qui ne sont pas des index primaire* (dans l'absolu une clef primaire peut etre sur plusieurs colonnes)
--> cf pg_class, pg_attribute, pg_index.
* construire la requete désirée grace a cette liste
(brouillon) ca donne qqchose genre:
DO $$
declare v_query_part text;
begin
select array_to_string((select array_agg(quote_ident( attname ) ) from pg_class,pg_attribute,pg_index where .... ), ',') into v_query_part ;
-- en admettant qu'il y a uniquement des PK sur une colonne, nommée "id" -- il est possible de récupérer cela a part dans une autre variable comme 'v_query_pk'
execute 'insert into .... (id,v_query_part) values ( select DEFAULT,v_query_part from ..... ');
end;
$$;
ce doit etre assez facile et peut-etre plus interessant de faire dans une fonction au final : function copy_row(p_tablename regclass, p_oldid int) ....
Cédric Villemain +33 (0)6 20 30 22 52
http://2ndQuadrant.fr/
PostgreSQL: Support 24x7 - Développement, Expertise et Formation
Hors ligne
Pages : 1