在 SQL Server 2016 中执行 "Cascading Insert" 是否有更简单的方法?
Is there an easier way to do a "Cascading Insert" in SQL Server 2016?
我继承了 SQL 我需要处理的代码,其设置类似于以下内容:
CREATE TABLE [dbo].[Ni](
[FooID] [int] IDENTITY(1,1) NOT NULL,
[Bar] [nvarchar](60) NULL,
[LocationID] [int] NULL,
[Thing1] [float] NULL
CONSTRAINT [PK_Ni] PRIMARY KEY CLUSTERED
(
[FooID] ASC
);
CREATE UNIQUE NONCLUSTERED INDEX [UQ_LocationBar] ON [dbo].[Ni]
(
[LocationID] ASC,
[Bar] ASC
);
CREATE TABLE [dbo].[Ni_Two](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FooID] [int] NOT NULL,
[Thing2] [int] NOT NULL,
[Thing3] [int] NOT NULL
CONSTRAINT [PK_Ni_Two] PRIMARY KEY CLUSTERED
(
[ID] ASC
);
ALTER TABLE [dbo].[Ni_Two] WITH CHECK ADD CONSTRAINT [FK_NiTwo_FooID] FOREIGN KEY([FooID])
REFERENCES [dbo].[Ni] ([FooID]);
CREATE TABLE [dbo].[KillMe](
[ID] [int] NOT NULL,
[FooID] [int] NULL,
[Thing4] [int] NOT NULL,
[Thing5] [int] NOT NULL
PRIMARY KEY CLUSTERED
(
[ID] ASC
);
ALTER TABLE [dbo].[KillMe] WITH NOCHECK ADD CONSTRAINT [FK_KillMe_FooID] FOREIGN KEY([FooID])
REFERENCES [dbo].[Ni] ([FooID]);
CREATE TABLE [dbo].[PleaseStop](
[ID] [int] NOT NULL,
[KillMeID] [int] NOT NULL,
[Thing7] [int] NOT NULL,
[Thing8] [int] NOT NULL
PRIMARY KEY CLUSTERED
(
[Id] ASC
);
ALTER TABLE [dbo].[PleaseStop] WITH CHECK ADD CONSTRAINT [FK_PleaseStop_KillMe] FOREIGN KEY([KillMeID])
REFERENCES [dbo].[KillMe] ([ID]);
问题是这个设计是 [Ni].dbo.[Bar]
。该唯一约束是作为要求放在那里的。每个 FooID
都是唯一的,分配给 LocationID
的每个 Bar
也必须是唯一的。
现在要求已经改变了。每个季度导入都会有一些条目,其中 Bar
字段必须更新。
我试过:
UPDATE dbo.[Ni]
SET Bar = Imp.Bar
, LocationID = Imp.LocationID
, Thing1 = Imp.Thing1
FROM dbo.[Ni]
INNER JOIN ImportData Imp ON [Ni].FooID = Imp.FooID
这会给我一个 Violation of UNIQUE KEY constraint
错误。
我不想更改架构,因为我不知道它会对代码产生什么其他影响。该程序的作者此后离开了公司。 . .我在这里。
作为维护程序的一部分,该程序每季度运行一次(即一年四次)。
我可以在不使用 WHILE
语句的情况下执行此操作吗?因为那会很痛苦。
谢谢!
因此要么在单个查询中更新它们,例如
CREATE TABLE [dbo].[Ni](
[FooID] [int] IDENTITY(1,1) NOT NULL,
[Bar] [nvarchar](60) NULL,
[LocationID] [int] NULL,
[Thing1] [float] NULL
CONSTRAINT [PK_Ni] PRIMARY KEY CLUSTERED
(
[FooID] ASC
)
);
CREATE UNIQUE NONCLUSTERED INDEX [UQ_LocationBar] ON [dbo].[Ni]
(
[LocationID] ASC,
[Bar] ASC
);
insert into Ni(bar) values ('a'),('b'),('c');
with newValues as
(
select * from (values (1,'c'),(3,'x')) newValues (FooId, Bar)
),
toUpdate as
(
select ni.FooId, ni.Bar, NewValues.Bar NewBar
from Ni
join NewValues
on ni.FooID = newValues.FooId
)
update toUpdate set Bar = NewBar
或禁用并重建唯一索引
begin transaction
alter index [UQ_LocationBar] on ni disable
update ni set bar = 'b' where fooid = 1
update ni set bar = 'a' where fooid = 2
alter index [UQ_LocationBar] on ni rebuild
commit transaction
Am I allowed to disable and re-enable the constraint in a stored procedure?
当然,它需要额外的权限,但对 运行 存储过程中的 DDL 没有限制,并且在 SQL 服务器 DDL 是完全事务性的,因此您可以 commit/rollback以防止部分更新并防止其他会话看到部分结果。
我继承了 SQL 我需要处理的代码,其设置类似于以下内容:
CREATE TABLE [dbo].[Ni](
[FooID] [int] IDENTITY(1,1) NOT NULL,
[Bar] [nvarchar](60) NULL,
[LocationID] [int] NULL,
[Thing1] [float] NULL
CONSTRAINT [PK_Ni] PRIMARY KEY CLUSTERED
(
[FooID] ASC
);
CREATE UNIQUE NONCLUSTERED INDEX [UQ_LocationBar] ON [dbo].[Ni]
(
[LocationID] ASC,
[Bar] ASC
);
CREATE TABLE [dbo].[Ni_Two](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FooID] [int] NOT NULL,
[Thing2] [int] NOT NULL,
[Thing3] [int] NOT NULL
CONSTRAINT [PK_Ni_Two] PRIMARY KEY CLUSTERED
(
[ID] ASC
);
ALTER TABLE [dbo].[Ni_Two] WITH CHECK ADD CONSTRAINT [FK_NiTwo_FooID] FOREIGN KEY([FooID])
REFERENCES [dbo].[Ni] ([FooID]);
CREATE TABLE [dbo].[KillMe](
[ID] [int] NOT NULL,
[FooID] [int] NULL,
[Thing4] [int] NOT NULL,
[Thing5] [int] NOT NULL
PRIMARY KEY CLUSTERED
(
[ID] ASC
);
ALTER TABLE [dbo].[KillMe] WITH NOCHECK ADD CONSTRAINT [FK_KillMe_FooID] FOREIGN KEY([FooID])
REFERENCES [dbo].[Ni] ([FooID]);
CREATE TABLE [dbo].[PleaseStop](
[ID] [int] NOT NULL,
[KillMeID] [int] NOT NULL,
[Thing7] [int] NOT NULL,
[Thing8] [int] NOT NULL
PRIMARY KEY CLUSTERED
(
[Id] ASC
);
ALTER TABLE [dbo].[PleaseStop] WITH CHECK ADD CONSTRAINT [FK_PleaseStop_KillMe] FOREIGN KEY([KillMeID])
REFERENCES [dbo].[KillMe] ([ID]);
问题是这个设计是 [Ni].dbo.[Bar]
。该唯一约束是作为要求放在那里的。每个 FooID
都是唯一的,分配给 LocationID
的每个 Bar
也必须是唯一的。
现在要求已经改变了。每个季度导入都会有一些条目,其中 Bar
字段必须更新。
我试过:
UPDATE dbo.[Ni]
SET Bar = Imp.Bar
, LocationID = Imp.LocationID
, Thing1 = Imp.Thing1
FROM dbo.[Ni]
INNER JOIN ImportData Imp ON [Ni].FooID = Imp.FooID
这会给我一个 Violation of UNIQUE KEY constraint
错误。
我不想更改架构,因为我不知道它会对代码产生什么其他影响。该程序的作者此后离开了公司。 . .我在这里。
作为维护程序的一部分,该程序每季度运行一次(即一年四次)。
我可以在不使用 WHILE
语句的情况下执行此操作吗?因为那会很痛苦。
谢谢!
因此要么在单个查询中更新它们,例如
CREATE TABLE [dbo].[Ni](
[FooID] [int] IDENTITY(1,1) NOT NULL,
[Bar] [nvarchar](60) NULL,
[LocationID] [int] NULL,
[Thing1] [float] NULL
CONSTRAINT [PK_Ni] PRIMARY KEY CLUSTERED
(
[FooID] ASC
)
);
CREATE UNIQUE NONCLUSTERED INDEX [UQ_LocationBar] ON [dbo].[Ni]
(
[LocationID] ASC,
[Bar] ASC
);
insert into Ni(bar) values ('a'),('b'),('c');
with newValues as
(
select * from (values (1,'c'),(3,'x')) newValues (FooId, Bar)
),
toUpdate as
(
select ni.FooId, ni.Bar, NewValues.Bar NewBar
from Ni
join NewValues
on ni.FooID = newValues.FooId
)
update toUpdate set Bar = NewBar
或禁用并重建唯一索引
begin transaction
alter index [UQ_LocationBar] on ni disable
update ni set bar = 'b' where fooid = 1
update ni set bar = 'a' where fooid = 2
alter index [UQ_LocationBar] on ni rebuild
commit transaction
Am I allowed to disable and re-enable the constraint in a stored procedure?
当然,它需要额外的权限,但对 运行 存储过程中的 DDL 没有限制,并且在 SQL 服务器 DDL 是完全事务性的,因此您可以 commit/rollback以防止部分更新并防止其他会话看到部分结果。