0

ID列または HANAシーケンスの使用は許可されていませんが、手動でテーブルの一意の自動インクリメント キーを生成する必要があります。これは、一意のカウンターをテーブルに格納TABLEKEYSし、実行ごとにインクリメントする、安全で単純なキー生成手順です。

CREATE PROCEDURE NewKey
(   IN  SeqName   NVARCHAR( 32),
    OUT NewKey    BIGINT
)
AS  rec_exists  INT;
    row_num     INT;
BEGIN
    SELECT SUM(1) INTO rec_exists
    FROM ( SELECT TOP 1 1 FROM TABLEKEYS WHERE "Name" = :SeqName ) T;
    IF :rec_exists IS NULL THEN         
        SELECT COALESCE(SUM(1),0) INTO row_num FROM TABLEKEYS;

        INSERT INTO TABLEKEYS("Code",  "Name",    "U_CurrentKey")
        VALUES               (row_num, :SeqName,  -1            );
    END IF;

    UPDATE TABLEKEYS SET "U_CurrentKey" = "U_CurrentKey" + 1
    WHERE "Name" = :SeqName;

    SELECT "CurrentKey" INTO NewKey FROM TABLEKEYS
    WHERE "Name" = :SeqName;
END;

100 の同時接続から集中的に呼び出された場合でも、どのような状況でも 2 つの同一のキーを返さないように、信頼性を高めるにはどうすればよいですか? MSSQL Server では、その本体をトランザクションでラップし、最初のクエリでロック ヒントをテーブルに適用する必要がありますが、HANA での類似物については知りません。HANA で、テーブルの行が厳密に順次アクセスされるようにする方法はありますか?

Lars によって提案され、Business One ユーザー定義テーブルに適応した修正を含む私の手順:

CREATE PROCEDURE GTGetNewKeyInt
(   IN  TableName NVARCHAR( 32),
    OUT NewKey    BIGINT
)
AS  cur_key     INT;
    row_num     INT;
    row_num_txt VARCHAR(8);
BEGIN
    BEGIN
        DECLARE EXIT HANDLER FOR SQLEXCEPTION
        BEGIN
        END;
        SELECT "U_CurrentKey" INTO cur_key FROM "@GTTABLEKEYS"
        WHERE "Name" = :TableName
        FOR UPDATE;
    END;

    IF :cur_key IS NULL THEN
        LOCK TABLE "@GTTABLEKEYS" IN EXCLUSIVE MODE;
        SELECT COALESCE(SUM(1),0) INTO row_num FROM "@GTTABLEKEYS";
        row_num_txt = LPAD( CAST( row_num AS varchar ), 8, '0' );
        NewKey = 0;
        INSERT INTO "@GTTABLEKEYS"("Code",      "Name",      "U_CurrentKey")
        VALUES                    (row_num_txt, :TableName,  :NewKey       );
    ELSE
        NewKey = :cur_key + 1;
        UPDATE "@GTTABLEKEYS" SET "U_CurrentKey" = :NewKey
        WHERE "Name" = :TableName;
    END IF;
END;
4

1 に答える 1

1

まず、シーケンスや IDENTITY 列などの組み込み機能を使用しないことは、あまり良い考えとは言えません。

ここで自分で構築したものは、いずれかの点で劣ります。でも、結局のところ、それはあなたのコードです。

したがって、ロックを使用して選択するには、標準の SQL コマンドがあります。

SELECT ... FOR UPDATE FROM...

(こちらのドキュメントも参照してください)

あなたのプログラムロジックは

  1. SELECT ... FOR UPDATE
  2. やるべきことは何でもする
  3. シーケンス テーブルを更新する
  4. コミットまたはロールバック

レコードはステップ 1 の時点でロックされます。プロセス全体をより効率的にし、シーケンスを管理するパフォーマンスを実際のデータ テーブルのデータ量から分離するために、シーケンスを独自のテーブルに保持することができます。 (単一のレコードと多数の更新を処理するため、行ストアはこれに適している可能性があります)。これは、シーケンスがどのように機能するかにかなり近いです。

于 2016-11-23T16:59:43.963 に答える