web-dev-qa-db-ja.com

PostgreSQLのシーケンスの次の価値は?

Codeigniter WebサイトにPostgreSQLを使用しています。追加、編集、削除の操作に食料品の塊を使用しています。編集または追加を行っている間、コンテンツのIDに基づいて、アップロードされたファイルの名前を動的に変更します。私は食料品のcrudの_callback_after_upload_関数を使用してこれを行うことができます。

新しいコンテンツを追加するときに、コンテンツの次のIDが必要です。 nextval()関数を使用しようとしましたが、シーケンスが増加します。 nextval()関数を使用せずにシーケンスの最後の値を取得するにはどうすればよいですか?

または、これを行う簡単な方法はありますか?

29
i_nomad

RETURNING

現代のPostgreSQL(8.2以降)では、データベースに対して1回の往復でこれを行います。

_INSERT INTO tbl(filename)
VALUES ('my_filename')
RETURNING tbl_id;
_

_tbl_id_は serial 列です。 マニュアルの詳細

明示的に値を取得する

filenameに_tbl_id_(冗長)を含める必要がある場合でも、単一のクエリを使用できます。
lastval() またはより具体的な currval()

_INSERT INTO tbl (filename)
VALUES ('my_filename' || lastval())  -- or currval('tbl_tbl_id_seq')
RETURNING tbl_id;
_

lastval():に関するマニュアル

この関数は、シーケンス名を引数として取る代わりに、現在のセッションでcurrvalが使用する最後のシーケンスの値を取得することを除いて、nextvalと同じです。

テーブルにリンクされた複数のシーケンスがある場合(またはトリガーを持つ場合でも)、sureの方法はcurrval('tbl_tbl_id_seq')を使用することです。

シーケンス名

文字列リテラル _'tbl_tbl_id_seq'_は、actualシーケンスの名前であると想定され、regclassにキャストされ、例外が発生します現在の _search_path_ でその名前のシーケンスが見つからない場合。

_tbl_tbl_id_seq_は、シリアル列_tbl_id_を持つテーブルtblに対して自動的に生成されるデフォルトです。しかし、保証はありません。列のデフォルトは、定義されている場合、anyシーケンスから値をフェッチできます。また、テーブルの作成時にデフォルト名が使用される場合、Postgresはハードコーディングされたアルゴリズムに従って次の空き名を選択します。

しない場合knowserial列のシーケンスの名前は、専用関数 pg_get_serial_sequence() オンザフライでも実行できます。

_INSERT INTO tbl (filename)
VALUES ('my_filename' || currval(pg_get_serial_sequence('tbl', 'tbl_id'))
RETURNING tbl_id;
_

SQL Fiddle。

35

以前に取得したシーケンスの値には、currval()関数を使用してアクセスします。

しかし、それはnextval()before thatと呼ばれた場合のみ値を返します。

実際にシーケンスを取得しないと、シーケンスの次の値を「覗く」方法はまったくありません。

しかし、あなたの質問は不明です。挿入を行う前にnextval()を呼び出すと、その値を挿入で使用できます。または、さらに良いことに、挿入ステートメントでcurrval()を使用します。

select nextval('my_sequence') ...

... do some stuff with the obtained value

insert into my_table(id, filename)
values (currval('my_sequence'), 'some_valid_filename');
17

どうにかしてこれを行うことができたとしても、それは別のレコードで使用されるシーケンスを取得することができるため、ひどい考えです!

より良いアイデアは、レコードを保存し、その後シーケンスを取得することです。

0
Brian

セッションに参加していない場合は、nextval( 'you_sequence_name')を実行するだけで問題ありません。

0
Irlan Cidade

私はこれを試してみましたが、完全に動作します

@Entity
public class Shipwreck {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
  @Basic(optional = false)
  @SequenceGenerator(name = "seq", sequenceName = "shipwreck_seq", allocationSize = 1)
  Long id;

....

CREATE SEQUENCE public.shipwreck_seq
    INCREMENT 1
    START 110
    MINVALUE 1
    MAXVALUE 9223372036854775807
    CACHE 1;
0
user2699843

あなたの質問に文字通り答えるために、シーケンスをインクリメントせずに次の値を取得する方法は次のとおりです。

SELECT
 CASE WHEN is_called THEN
   last_value + 1
 ELSE
   last_value
 END
FROM sequence_name

明らかに、実際にこのコードを使用するのは得策ではありません。 次の行が実際にこのIDを持っているという保証はありません。ただし、デバッグのために、シーケンスの値をインクリメントせずに知ることは興味深いかもしれません。これがその方法です。

0
Jakob Egger