SQLサーバーでシーケンスのようなものを実装する良い方法はありますか?
場合によっては、GUID が醜いという事実以外に、GUID を使用したくない場合もあります。たぶん、あなたが望むシーケンスは数値ではありませんか? その上、行を挿入してからDBに番号を尋ねるのは、とてもハックに思えます。
SQLサーバーでシーケンスのようなものを実装する良い方法はありますか?
場合によっては、GUID が醜いという事実以外に、GUID を使用したくない場合もあります。たぶん、あなたが望むシーケンスは数値ではありませんか? その上、行を挿入してからDBに番号を尋ねるのは、とてもハックに思えます。
Sql Server 2012 ではSEQUENCE
オブジェクトが導入されました。これにより、テーブルに関連付けられていない連続した数値を生成できます。
それらの作成は簡単です:
CREATE SEQUENCE Schema.SequenceName
AS int
INCREMENT BY 1 ;
挿入前の使用例:
DECLARE @NextID int ;
SET @NextID = NEXT VALUE FOR Schema.SequenceName;
-- Some work happens
INSERT Schema.Orders (OrderID, Name, Qty)
VALUES (@NextID, 'Rim', 2) ;
シーケンスの使用方法の詳細については、私のブログを参照してください。
http://sqljunkieshare.com/2011/12/11/sequences-in-sql-server-2012-implementingmanaging-performance/
Identity 列は、シーケンスにほぼ似ています。
普通の古いテーブルを使用して、それらをシーケンスとして使用できます。つまり、挿入は常に次のようになります。
BEGIN TRANSACTION
SELECT number from plain old table..
UPDATE plain old table, set the number to be the next number
INSERT your row
COMMIT
しかし、これをしないでください。ロックはダメだろうな…
私は SQL Server から始めましたが、Oracle の「シーケンス」スキームはハックのように見えました。私はあなたが別の方向からあなたに来ていると思います.scope_identity()はハックのように見えます.
それを乗り越えてください。ローマにいるときは、ローマ人がするようにしなさい。
この問題を解決するために使用した方法は、すべてのシーケンスと「nextval」ストアド プロシージャを格納するテーブル「Sequences」でした。
SQL テーブル:
CREATE TABLE Sequences (
name VARCHAR(30) NOT NULL,
value BIGINT DEFAULT 0 NOT NULL,
CONSTRAINT PK_Sequences PRIMARY KEY (name)
);
PK_Sequencesは、同じ名前のシーケンスが存在しないようにするために使用されます 。
SQL ストアド プロシージャ:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'nextVal') AND type in (N'P', N'PC')) DROP PROCEDURE nextVal;
GO
CREATE PROCEDURE nextval
@name VARCHAR(30)
AS
BEGIN
DECLARE @value BIGINT
BEGIN TRANSACTION
UPDATE Sequences
SET @value=value=value + 1
WHERE name = @name;
-- SELECT @value=value FROM Sequences WHERE name=@name
COMMIT TRANSACTION
SELECT @value AS nextval
END;
いくつかのシーケンスを挿入します:
INSERT INTO Sequences(name, value) VALUES ('SEQ_Workshop', 0);
INSERT INTO Sequences(name, value) VALUES ('SEQ_Participant', 0);
INSERT INTO Sequences(name, value) VALUES ('SEQ_Invoice', 0);
最後にシーケンスの次の値を取得し、
execute nextval 'SEQ_Participant';
シーケンス テーブルから次の値を取得するいくつかの c# コード、
public long getNextVal()
{
long nextval = -1;
SqlConnection connection = new SqlConnection("your connection string");
try
{
//Connect and execute the select sql command.
connection.Open();
SqlCommand command = new SqlCommand("nextval", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@name", SqlDbType.NVarChar).Value = "SEQ_Participant";
nextval = Int64.Parse(command.ExecuteScalar().ToString());
command.Dispose();
}
catch (Exception) { }
finally
{
connection.Dispose();
}
return nextval;
}
SQL Server 2012 では、単純に使用できます。
CREATE SEQUENCE
2005 および 2008 では、共通のテーブル式を使用して連番の任意のリストを取得できます。
次に例を示します (MAXRECURSION オプションが重要であることに注意してください)。
DECLARE @MinValue INT = 1;
DECLARE @MaxValue INT = 1000;
WITH IndexMaker (IndexNumber) AS
(
SELECT
@MinValue AS IndexNumber
UNION ALL SELECT
IndexNumber + 1
FROM
IndexMaker
WHERE IndexNumber < @MaxValue
)
SELECT
IndexNumber
FROM
IndexMaker
ORDER BY
IndexNumber
OPTION
(MAXRECURSION 0)
Oracle によって実装されているシーケンスでは、挿入の前にデータベースへの呼び出しが必要です。SQL Server によって実装される ID では、挿入後にデータベースへの呼び出しが必要です。
一方は他方よりもハックではありません。最終的な効果は同じです。一意の人工キー値を提供するためのデータ ストアへの依存/依存と、(ほとんどの場合) ストアへの 2 つの呼び出しです。
あなたのリレーショナル モデルは人工キーに基づいていると想定しています。このコンテキストでは、次の観察結果を提供します。
人工的な鍵に意味を持たせようとしてはなりません。それらの唯一の目的は、関連するレコードをリンクすることです。
データの注文に関して、どのようなニーズがありますか? ビュー(プレゼンテーション)で処理できますか、それとも永続化する必要があるデータの真の属性ですか?
識別子を持つステージ テーブルを作成します。
ステージ テーブルをロードする前に、識別子を切り捨てて再シードし、1 から開始します。
テーブルをロードします。各行には、1 から N までの一意の値が含まれるようになりました。
シーケンス番号を保持するテーブルを作成します。これは、シーケンスごとに 1 つずつ、複数の行になる場合があります。
作成したシーケンス テーブルからシーケンス番号を検索します。ステージ テーブルの行数をシーケンス番号に追加して、シーケンス番号を更新します。
検索したシーケンス番号を追加して、ステージ テーブル識別子を更新します。これは簡単な 1 ステップのプロセスです。または ターゲット テーブルをロードし、ETL にロードする際に識別子にシーケンス番号を追加します。これにより、一括ローダーを利用して、他の変換を行うことができます。
sqljunkiesshare が述べているように、SQL Server 2012 にシーケンスが追加されました。GUI でそれを行う方法は次のとおりです。これは次のものと同等です。
CREATE SEQUENCE Schema.SequenceName
AS int
INCREMENT BY 1 ;
ノート:
デフォルトの開始値、最小値、および最大値は、この場合は int であるデータ型の範囲によって決定されました。int 以外のものを使用する場合は、データ型の範囲についてはこちらを参照してください。
シーケンスを 1 から開始し、最小値も 1 にしたい場合があります。
私は完全に同意し、昨年プロジェクトでこれを行いました。
シーケンスの名前、現在の値、および増分量を含むテーブルを作成しました。
次に、それらを追加および削除するための2つのprocを作成しました。そして、次を取得するための2つの機能と、最新のものを取得します。
ID 列のもう 1 つの問題は、シーケンス番号を一意にする必要があるテーブルが複数ある場合、ID 列が機能しないことです。また、Corey Trager が言及しているように、ロール ユア オウン タイプのシーケンス実装では、ロックの問題が発生する可能性があります。
最も直接的に同等のソリューションは、ID 用の単一の列を持つ SQL Server テーブルを作成することのようです。これは、別のタイプの「シーケンス」オブジェクトの代わりになります。たとえば、Oracle で Dogs <-- sequence object --> Cats などの 1 つのシーケンスから 2 つのテーブルがある場合、SQL Server では 3 つのデータベース オブジェクトを作成します。すべてのテーブルは Dogs <-- Pets with identity column --> のようになります。猫。Pets テーブルに行を挿入して、通常は NEXTVAL を使用するシーケンス番号を取得し、ユーザーから実際のペットの種類を取得したら、通常どおりに Dogs または Cats テーブルに挿入します。追加の共通列は、Dogs/Cats テーブルから Pets スーパータイプ テーブルに移動できます。その結果、1) シーケンス番号ごとに 1 つの行が存在することになります。
SQL Server 2005 を使用している場合は、Row_Number を使用するオプションがあります
シーケンシャルキーを使用してデータを挿入したいが、挿入したばかりのキーを取得するためにデータベースに再度クエリを実行する必要がない場合は、次の 2 つの選択肢しかないと思います。
クライアント側のキー生成を行っている場合、GUIDが大好きです。私は彼らがめちゃくちゃ美しいと思います。
row["ID"] = Guid.NewGuid();
そのラインは、スポーツカーのボンネットのどこかにあるはずです。