9

MS Sql Server では、自動インクリメント フィールドを簡単に作成できます。私のシステムでは、主キーに自動インクリメント フィールドを使用するのをやめ、現在は Guid を使用しています。それは素晴らしかったです、私はその変更で多くの利点を持っています. しかし、別の非主キー フィールドでは、「ソフト オートインクリメント」を実装する必要がありました。私のシステムは DB に依存しないため、C# でプログラムによって autoinc 値を作成します。

自動インクリメントのないデータベースの自動インクリメント フィールドの解決策について教えてください。どのような解決策を使用し、その理由は何ですか? これについていくつかのSql Ansiステートメントがありますか? 私のC#から直接生成するのは、より良い解決策ですか?

PS:テーブルから max(id)+1 を選択することは、実際には同時実行に適していないことを知っています...

4

5 に答える 5

2

あなたの質問は実際にはかなり良いものだと思います。ただし、SQL のみのソリューションを考え出そうとすると、迷子になりがちです。実際には、自動インクリメント型のデータベース実装を使用することによって提供される最適化とトランザクションの安全性が必要になります。

自動インクリメント演算子の実装を抽象化する必要がある場合は、自動インクリメント値を返すストアド プロシージャを作成しないでください。ほとんどの SQL ダイアレクトは比較的同じ方法でストアド プロシージャにアクセスするため、より移植性が高いはずです。次に、sproc を作成するときにデータベース固有の自動インクリメント ロジックを作成できます。これにより、多くのステートメントをベンダー固有に変更する必要がなくなります。

このようにすると、挿入は次のように簡単になります。

INSERT INTO foo (id, name, rank, serial_number)
 VALUES (getNextFooId(), 'bar', 'fooRank', 123456);

次に、データベースの初期化時にデータベース固有の方法で getNextFooId() を定義します。

于 2009-02-10T09:51:08.973 に答える
1

SQL Server (具体的には Oracle だと思います) のような自動インクリメント フィールドを持たないほとんどのデータベースには、Sequence に次の番号を要求するシーケンスがあります。何人が同時に番号を要求しても、全員が一意の番号を取得します。

于 2009-02-08T21:42:51.323 に答える
1

従来の解決策は、次のような ID のテーブルを用意することです。

CREATE TABLE ids (
  tablename VARCHAR(32) NOT NULL PRIMARY KEY,
  nextid INTEGER
)

データベースを作成すると、テーブルごとに 1 つの行が入力されます。

次に、select を実行して、挿入先のテーブルの次の次の ID を取得し、それをインクリメントしてから、新しい ID でテーブルを更新します。明らかに、ここにはロックの問題がありますが、挿入率が中程度のデータベースではうまく機能します。そして、それは完全に移植可能です。

于 2009-02-08T21:47:35.540 に答える
0

主キー以外の自動インクリメント フィールドが必要な場合、調停シーケンスを作成するための非常に優れた MySQL のみのソリューションは、比較的未知のlast_insert_id(expr)関数を使用することです。

expr が LAST_INSERT_ID() の引数として与えられた場合、引数の値は関数によって返され、LAST_INSERT_ID() によって返される次の値として記憶されます。これは、シーケンスをシミュレートするために使用できます...

( http://dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_last-insert-idから)

これは、各投稿のコメントに番号を付けるために二次シーケンスを保持する方法を示す例です:

CREATE TABLE  `post` (
  `id` INT(10) UNSIGNED NOT NULL,
  `title` VARCHAR(100) NOT NULL,
  `comment_sequence` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
);

CREATE TABLE  `comment` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `post_id`  INT(10) UNSIGNED NOT NULL,
  `sequence` INT(10) UNSIGNED NOT NULL,
  `content` TEXT NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO post(id, title) VALUES(1, 'first post');
INSERT INTO post(id, title) VALUES(2, 'second post');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=1;
INSERT INTO `comment`(post_id, sequence, content) VALUES(1, Last_insert_id(), 'blah');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=1;
INSERT INTO `comment`(post_id, sequence, content) VALUES(1, Last_insert_id(), 'foo');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=1;
INSERT INTO `comment`(post_id, sequence, content) VALUES(1, Last_insert_id(), 'bar');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=2;
INSERT INTO `comment`(post_id, sequence, content) VALUES(2, Last_insert_id(), 'lorem');

UPDATE post SET comment_sequence=Last_insert_id(comment_sequence+1) WHERE id=2;
INSERT INTO `comment`(post_id, sequence, content) VALUES(2, Last_insert_id(), 'ipsum');

SELECT * FROM post;
SELECT * FROM comment;
于 2011-02-07T12:25:27.930 に答える