テーブルがあれば
Table
{
ID int primary key identity,
ParentID int not null foreign key references Table(ID)
}
どのようにして最初の行をテーブルに挿入しますか?
ビジネスロジックの観点からは、ParentIDのnull以外の制約を削除しないでください。
テーブルがあれば
Table
{
ID int primary key identity,
ParentID int not null foreign key references Table(ID)
}
どのようにして最初の行をテーブルに挿入しますか?
ビジネスロジックの観点からは、ParentIDのnull以外の制約を削除しないでください。
SQL Serverでは、単純なINSERTで次のことが行われます。
create table dbo.Foo
(
ID int primary key identity,
ParentID int not null foreign key references foo(ID)
)
go
insert dbo.Foo (parentId) values (1)
select * from dbo.Foo
結果は
ID ParentID
----------- -----------
1 1
IDシードとは異なる値を挿入しようとすると、挿入は失敗します。
アップデート:
コンテキストが何であるか(つまり、ライブの本番システムで機能するはずのコードか、DBセットアップスクリプトだけか)についての質問はあまり明確ではなく、コメントから、IDをハードコーディングすることはオプションではないようです。上記のコードは通常、階層ルートIDが既知で一定である必要があるDB初期化スクリプトで正常に機能するはずですが、フォレスト(事前にIDが不明ないくつかのルート)の場合、以下は意図したとおりに機能するはずです。
create table dbo.Foo
(
ID int primary key identity,
ParentID int not null foreign key references foo(ID)
)
go
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
次に、通常どおり最後のIDを照会できます(SCOPE_IDENTITY
など)。@usrの懸念に対処するために、次の例が示すように、コードは実際にはトランザクション上安全です。
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
select * from dbo.Foo
select IDENT_CURRENT('dbo.Foo')
begin transaction
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
rollback
select IDENT_CURRENT('dbo.Foo')
insert dbo.Foo (parentId) values (IDENT_CURRENT('dbo.Foo'))
select * from dbo.Foo
結果:
ID ParentID
----------- -----------
1 1
2 2
3 3
currentIdentity
---------------------------------------
3
currentIdentity
---------------------------------------
4
ID ParentID
----------- -----------
1 1
2 2
3 3
5 5
最初のIDに明示的な値を使用する必要がある場合は、最初のレコードを挿入するときに、IDENTITY値のチェックを無効にすることができます(MSDN:SET IDENTITY_INSERT(Transact-SQL)を参照)。
これを説明する例を次に示します。
CREATE TABLE MyTable
(
ID int PRIMARY KEY IDENTITY(1, 1),
ParentID int NOT NULL,
CONSTRAINT MyTable_ID FOREIGN KEY (ParentID) REFERENCES MyTable(ID)
);
SET IDENTITY_INSERT MyTable ON;
INSERT INTO MyTable (ID, ParentID)
VALUES (1, 1);
SET IDENTITY_INSERT MyTable OFF;
WHILE @@IDENTITY <= 5
BEGIN
INSERT INTO MyTable (ParentID)
VALUES (@@IDENTITY);
END;
SELECT *
FROM MyTable;
IF OBJECT_ID('MyTable') IS NOT NULL
DROP TABLE MyTable;
NOT NULL
ツリーのルートノードには制約が当てはまらないようです。単に親がありません。したがって、最初から破られてParentID
いるという仮定。NOT NULL
null許容にし、インデックスを追加してParentID
、値を持つものが1つしかないことを検証することをお勧めしますNULL
。
create unique nonclustered index ... on T (ParentID) where (ParentID IS NULL)
SQLServerで健全なツリー構造を強制することは困難です。たとえば、グラフ内の複数のルートまたはサイクルを取得できます。それをすべて検証することは困難であり、努力する価値があるかどうかは不明です。特定のケースによっては、そうなる可能性があります。