多个用户可以调用存储过程(SP),这将对SQL Server 中的mytable 进行一些更改。此 SP 应向 mytable 插入一些行,这些行通过 parentid 列引用了自身。
TABLE mytable(
id int identity(1,1) primary key,
name varchar(20) not null,
parentId int not null foreign key references mytable(id)
)
为了向此类表中插入行,根据其他帖子,我有两种方法:
- 通过
ALTER TABLE mytable alter column parentid int null;
允许parentid 列为空,插入行,更新 parentid 并禁用 null 到 parentid - 通过
set identity_insert maytable on
允许IDENTITY ,插入带有id=-1 和parentid=-1 的虚拟行,插入引用-1 的正确行,更新parentid 到 SCOPE_IDENTITY() 最后将 IDENTITY 设置为 off
案例:
假设我采用第二种方式。 SP 设法 set identity_insert mytable on
BUT 尚未完成其余 SP 的执行。此时,还有其他 INSERT 请求(不是通过 SP)到 mytable 表,如 INSERT INTO mytable(name,parentid) VALUES('theateist', -1)
.没有指定 id,因为他们假定 IDENTITY 已关闭,因此 id 是自动递增的。
问题:
这会不会导致插入时出错,因为IDENTITY在这段时间内是ON的,不再自增,因此需要指定id?如果是,使用第一种方式会更好,不是吗?
谢谢
最佳答案
identity_insert
是针对每个连接的设置 - 您不会影响针对此表运行的其他连接/语句。
如果可以避免的话,我绝对不会建议采用第一种方式,因为它可能会影响表格的其他用户 - 例如当列定义允许时,其他一些连接可能会中断插入 (parentid=null
),然后您的存储过程将中断。此外,设置一列 not null
会强制进行全表扫描,因此随着表的增长,这将无法正常工作。
如果您确实坚持使用方法 2,您仍然会遇到如果两个连接同时运行此存储过程会发生什么情况的问题 - 他们都想插入 -1
行,在不同的时间,也删除它。你会有冲突。
我猜你遇到的问题是插入树的“根”,因为它们没有父代,所以你试图让它们自引用。相反,我可能会使根永久具有空的 parentid。如果有一些其他键列,这些可以用于过滤索引或索引 View ,以确保每个键只存在一个根。
想象一下,我们正在构建某种形式的家谱,而忽略了此类野兽的大部分现实(例如大多数要求 child 有两个 parent 的家庭):
CREATE TABLE People (
PersonID int IDENTITY(1,1) not null,
Surname varchar(30) not null,
Forename varchar(30) not null,
ParentID int null,
constraint PK_People PRIMARY KEY (PersonID),
constraint FK_People_Parents FOREIGN KEY (ParentID) references People (PersonID)
)
CREATE UNIQUE INDEX IX_SoleFamilyRoot ON People (Surname) WHERE (ParentID is null)
这确保在每个家庭(由姓氏标识)中,只有一个人的 ParentID
为空。希望您可以修改此示例以适合您的模型。
在 SQL Server 2005 及更早版本上,您必须改用索引 View 。
关于sql - 使用直接查询和存储过程将对同一个表的插入请求相乘会导致冲突吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6093681/