web-dev-qa-db-ja.com

INSERT INTO table FROM SELECT * with nextval()指定

レコードをコピーする必要がありますwithin 1つのフィールドのみを変更する同じテーブル。テーブルにデフォルトで生成されたシーケンス_entry_id_seq_がありますが、id列がSERIALであるかどうかはわかりません(確認方法は?)。

_\d tab_はこれだけを返します

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

だから問題は:簡単な方法でレコードをコピーしようとすると:

_insert into tab_entry select * from tab_entry where id = 3052;
_

エラーが発生します

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

デフォルトのシーケンスでは、デフォルトで次の値は生成されません。完全なテーブル指定(FROM tab(col1, col2, col3, ..., col N))なしで単一フィールドを挿入および変更できる簡潔な構文はありますか?

テーブルには多くのフィールドがあるので、コードの読みやすさに影響するため、すべてを記述したくありません。このようなものが欲しいのですが、この構文は機能しません

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

そして、このSELECT nextval('seq')アプローチは、一度に複数のレコードがある場合に機能しますか?

PsqlとPostgresのバージョンは9.6.2です。

3
Suncatcher

コメントで述べたように、そのようなタスクには特別な構文はありません。
関数の組み合わせを使用できます to_json(b)json(b)_set and 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;

しかし、すべての列を列挙するだけではそれほど単純ではないと思います。常にこの比較的単純なクエリを使用して、テーブルの列リストを取得できます。

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