web-dev-qa-db-fra.com

INSERT INTO table FROM SELECT * avec la spécification nextval ()

J'ai besoin de copier des enregistrements à l'intérieur la même table en changeant un seul champ. Ma table a une séquence générée par défaut entry_id_seq, Mais je ne suis pas sûr que la colonne id soit SERIE (comment vérifier cela?).

\d tab Renvoie juste ceci

      Column      |              Type              |            Modifiers            
 -----------------+--------------------------------+------------------------
       id         |             integer            |            not null
...
Indexes:
"tab_entry_pkey" PRIMARY KEY, btree (id)

Le problème est donc le suivant: lorsque j'essaie de copier un enregistrement de manière simplifiée:

insert into tab_entry select * from tab_entry where id = 3052;

ça jette une erreur

ERROR:  duplicate key value violates unique constraint "tab_entry_pkey"
DETAIL:  Key (id)=(3052) already exists.

La séquence par défaut ne génère pas la valeur suivante par défaut. Existe-t-il une syntaxe concise permettant d'insérer et de modifier un seul champ sans spécification complète de la table aka FROM tab(col1, col2, col3, ..., col N)?

La table a de nombreux champs, donc je ne veux pas tous les écrire, car cela affectera la lisibilité du code. Je veux quelque chose comme ça, mais cette syntaxe ne fonctionne pas

insert into tab_entry(id, *) select nextval('seq'), * from tab_entry where id = 3052;

Et cette approche SELECT nextval('seq') fonctionnera-t-elle s'il y a plusieurs enregistrements à la fois?

La version Psql et Postgres est 9.6.2.

3
Suncatcher

Comme indiqué dans les commentaires, il n'y a pas de syntaxe spéciale pour une telle tâche.
Vous pouvez utiliser une combinaison de fonctions to_json(b), json(b)_set et json(b)_populate_record :

--drop table if exists t;
create table t(i serial primary key, x int, y text, z timestamp);
insert into t values(default, 1, 'a', now()),(default, 2, 'b', now());

insert into t
select n.*
from t, jsonb_populate_record(
  null::t, 
  jsonb_set(
    to_jsonb(t.*),
    array['i'],
    to_jsonb(nextval('t_i_seq')))) as n;

select * from t;

Mais je pense que ce n'est pas beaucoup plus simple que d'énumérer toutes les colonnes. Vous pouvez toujours utiliser cette requête relativement simple pour obtenir la liste des colonnes du tableau:

select string_agg(attname,',' order by attnum)
from pg_attribute
where attrelid = 'public.t'::regclass and attnum > 0;
4
Abelisto