簡體   English   中英

插入自引用表

[英]insertion in a self referenced table

如果我有一張桌子

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

如何將第一行插入表中?

從業務邏輯的角度來看,不應該刪除ParentID上的空約束。

在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可能不是一個選項。 雖然上面的代碼通常可以在數據庫初始化腳本中正常工作,其中層次結構根ID可能需要知道並且是常量,但對於林(具有預先未知的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'))

然后可以像往常一樣查詢最后一個身份( 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約束不正確。 它根本就沒有父母。 因此,從一開始就打破了ParentIDNOT NULL的假設。

我建議你讓它可以為空並在ParentID上添加一個索引來驗證只有一個值為NULL

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

在SQL Server中很難強制實現聲音樹結構。 例如,您可以在圖表中獲得多個根或循環。 很難對所有這些進行驗證,目前還不清楚是否值得付出努力。 根據具體情況,可能會這樣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM