12

SERIAL主キーとltree列を持つテーブルがあり、その値をそれらの主キーの連結にしたいと考えています。例えば

id | path
----------
1    1
2    1.2
3    1.2.3
4    1.4
5    1.5

1つのクエリでそのような挿入を行う方法があるかどうか、私は興味があります.

INSERT INTO foo (id, ltree) VALUES (DEFAULT, THIS.id::text)

私はおそらくここで行き過ぎで、2 つのクエリ (トランザクションにグループ化) で行うべきことを 1 つのクエリで実行しようとしています。

4

2 に答える 2

13

CTE を使用して、シーケンスから値を一度取得し、繰り返し使用できます。

WITH cte AS (
   SELECT nextval('foo_id_seq') AS id
   )
INSERT INTO foo (id, ltree)
SELECT id, '1.' || id
FROM   cte;

データ変更コマンドを含む CTE には、 Postgres 9.1 以降が必要です。

シーケンスの名前がわからない場合は、 pg_get_serial_sequence()代わりに次を使用します。

WITH i AS (
   SELECT nextval(pg_get_serial_sequence('foo', 'id')) AS id
   )
INSERT INTO foo (id, ltree)
SELECT id, '1.' || id
FROM   i;

テーブル名「foo」が DB 内のすべてのスキーマで一意でない可能性がある場合は、スキーマ修飾します。また、名前のつづりが標準的でない場合は、二重引用符で囲む必要があります。

pg_get_serial_sequence('"My_odd_Schema".foo', 'id')



簡単なテストでは、@Mark のアイデアも機能する可能性があることが示されました。lastval()

INSERT INTO foo (ltree) VALUES ('1.' || lastval());
  • idクエリを省略できserialます。列は自動的に割り当てられます。違いはありません。

  • 行間に競合状態があってはなりません。マニュアルを引用します

currval

nextval現在のセッションでこのシーケンスに対してによって取得された最新の値を返します。nextval(このセッションでこのシーケンスに対して が一度も呼び出されていない場合は、エラーが報告されます。)これはセッション ローカルな値を返すため、現在のセッションが実行されてから他のセッションが実行されたかどうかに関係なく、予測可能な答えが得られますnextval

この関数は、シーケンスに対する特権を必要USAGEとします。SELECT

lastval

nextval現在のセッションでによって最後に返された値を返します。この関数はと同じですがcurrvalnextval、引数としてシーケンス名を使用する代わりに、現在のセッションで最後に適用されたシーケンスを参照する点が異なります。現在のセッションでまだ呼び出されていないlastval場合、呼び出すとエラーになります。nextval

この関数は、最後に使用されたシーケンスに対する権限を必要USAGEとします。SELECT

大胆強調鉱山。

しかし@Bernard がコメントしたように、結局失敗する可能性があります。2 番目の列を埋めるために呼び出される前に、デフォルト値が埋められる (そしてnextval()プロセスで呼び出される) という保証はありません。したがって、最初の解決策に固執し、確実にしてください。 lastval()ltreenextval()

于 2012-09-15T00:08:07.533 に答える
4

これは私のテストでうまくいきました:

INSERT INTO foo (id, ltree) VALUES (DEFAULT, (SELECT last_value from foo_id_seq));

現在の行ではなく最後のシーケンス値を参照するため、2 つの INSERT が同時に発生している場合、競合状態が発生していると思います。私は個人的にこれを行う傾向があります(疑似コード):

my $id = SELECT nextval('foo_id_seq');
INSERT INTO foo (id, ltree) VALUES ($id, '$id');
于 2012-09-14T23:38:12.360 に答える