8

エンタープライズ アプリケーションのデータ インポート手順をリファクタリングしていて、より良い解決策を見つけたいスニペットに出会いました。データをインポートするときは、データ セットごとに一意のエンティティを作成する必要があり、この ID を順番に割り当てるために使用されるフィールドにカウンターがあります。フィールドを読み取って次の空き ID を取得し、その後それをインクリメントして次回に備えます。

現時点では、これは「C」で記述された元のアプリで 2 つのステップで行われます。

   SELECT idnext FROM mytable;
   UPDATE mytable SET idnext = idnext + 1;

複数のプロセスが同じことを行う場合、明らかに競合状態が発生します。

編集:重要な相互要件:データベース/フィールド定義に触れることはできません。これにより、シーケンスが除外されます。

私たちは perl で書き直しています。私は同じことをしたいと思っていますが、より良いものです。原子的な解決策がいいでしょう。残念ながら、私の SQL スキルは限られているため、集合知に頼っています :-)

4

4 に答える 4

9

この特定のケースでは、前述のようにシーケンスが適切なソリューションです。ただし、将来、同じステートメントで何かを更新して値を返す必要がある場合は、次のRETURNING句を使用できます。

UPDATE atable SET foo = do_something_with(foo) RETURNING foo INTO ?

呼び出しコードが PL/SQL の場合は、? を置き換えます。ローカル PL/SQL 変数を使用。それ以外の場合は、プログラムで出力パラメーターとしてバインドできます。

編集:Perlについて言及したので、次のようなものが機能するはずです(テストされていません):

my $sth = $dbh->prepare('UPDATE mytable SET idnext = idnext + 1 returning idnext into ?');
my $idnext;
$sth->bind_param_inout(1, \$idnext, 8);
$sth->execute; # now $idnext should contain the value

DBIを参照してください。

于 2010-01-08T17:27:18.677 に答える
4

シーケンスを使用しないのはなぜですか?

任意の START WITH 値を使用して、シーケンスを 1 回作成します。

CREATE SEQUENCE mysequence
  START WITH 1
  MAXVALUE 999999999999999999999999999
  MINVALUE 1
  NOCYCLE
  NOCACHE
  NOORDER;

次に、実行時のアプリケーション コードで、次のステートメントを使用して次の値を取得できます。

SELECT mysequence.NEXTVAL
  INTO idnext
  FROM DUAL;

更新:シーケンスを使用することが推奨される方法ですが、データベースを変更できないため、RETURNING を使用すると状況に応じて機能することに同意します。

   UPDATE mytable 
      SET idnext = idnext + 1 
RETURNING idnext 
     INTO mylocalvariable;
于 2010-01-08T17:18:52.090 に答える
2

SELECT FOR UPDATE ステートメントを使用します。レコードに対する相互排他的な権利を保証します。

"更新を選択;

于 2010-01-08T17:31:20.553 に答える
0

シーケンスは仕事をします、例えばOracleシーケンスを見てください

于 2010-01-08T17:18:06.073 に答える