8

テーブルがあれば

Table
{
ID int primary key identity,
ParentID int not null foreign key references Table(ID)
}

どのようにして最初の行をテーブルに挿入しますか?

ビジネスロジックの観点からは、ParentIDのnull以外の制約を削除しないでください。

4

3 に答える 3

5

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
于 2012-11-10T09:17:53.193 に答える
2

最初の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;
于 2012-11-10T09:18:46.700 に答える
2

NOT NULLツリーのルートノードには制約が当てはまらないようです。単に親がありません。したがって、最初から破られてParentIDいるという仮定。NOT NULL

null許容にし、インデックスを追加してParentID、値を持つものが1つしかないことを検証することをお勧めしますNULL

create unique nonclustered index ... on T (ParentID) where (ParentID IS NULL)

SQLServerで健全なツリー構造を強制することは困難です。たとえば、グラフ内の複数のルートまたはサイクルを取得できます。それをすべて検証することは困難であり、努力する価値があるかどうかは不明です。特定のケースによっては、そうなる可能性があります。

于 2012-11-10T12:45:09.257 に答える