以下是该方案:
我有表格Request(RId)
,表格Service(SId)
和表格Mapping(MId)
。
现在首先在Request表中生成一个请求。然后创建其相关的n个服务。假设有1个请求有5个服务。现在有一个映射表,它维护表Request和表Service之间的关系。
映射表示例:
MId | RId | SId
----------------
1 | 1 | 2
2 | 1 | 3
3 | 1 | 4
4 | 2 | 5
5 | 2 | 6
6 | 3 | 8
现在,我有两种方法可以做到这一点:
第一遍:在数据库中向SP插入一项服务,执行插入,然后获取其ID并在Mapping
表中输入。意味着如果我有5个服务,我必须在后端进行5次。(插入服务并在单个SP中进行映射)(目前我正在使用)。
第二遍:将所有服务数据作为TableType传递到SP并插入到数据库并获取最后5个服务ID并通过while循环执行所有进入Mapping表的条目。意味着我只需要在后端进行一次,但如果有其他人为他/她的请求插入服务,我将得到错误的ID并将错误地进行映射。
有没有更好的方法呢?
答案 0 :(得分:3)
您可以使用OUTPUT
子句从多个插入的行中捕获标识。在下面,我假设ServiceName
和RequestName
足以唯一地标识传入的值。如果不是,那么希望你能适应下面的内容(你没有真正定义)在问题中任何可用的非标识列名称或值):
首先,设置表格:
create table Requests (RId int IDENTITY(1,1) not null primary key,RequestName varchar(10) not null)
create table Services (SId int IDENTITY(1,1) not null primary key,ServiceName varchar(10) not null)
create table Mappings (MId int IDENTITY(1,1) not null,RId int not null references Requests,SId int not null references Services)
现在声明传递给存储过程的TVP是什么(请注意,此脚本和下一个需要在此模拟中一起运行):
declare @NewValues table (
RequestName varchar(10) not null,
ServiceName varchar(10) not null
)
insert into @NewValues (RequestName,ServiceName) values
('R1','S1'),
('R1','S2'),
('R1','S3'),
('R2','S4'),
('R2','S5'),
('R3','S6')
然后,在SP内部,您将拥有如下代码:
declare @TmpRIDs table (RequestName varchar(10) not null,RId int not null)
declare @TmpSIDs table (ServiceName varchar(10) not null,SId int not null)
;merge into Requests r using (select distinct RequestName from @NewValues) n on 1=0
when not matched then insert (RequestName) values (n.RequestName)
output n.RequestName,inserted.RId into @TmpRIDs;
;merge into Services s using (select distinct ServiceName from @NewValues) n on 1=0
when not matched then insert (ServiceName) values (n.ServiceName)
output n.ServiceName,inserted.SId into @TmpSIDs;
insert into Mappings (RId,SId)
select RId,SId
from @NewValues nv
inner join
@TmpRIds r
on
nv.RequestName = r.RequestName
inner join
@TmpSIDs s
on
nv.ServiceName = s.ServiceName;
检查结果:
select * from Mappings
产生
MId RId SId
----------- ----------- -----------
1 1 1
2 1 2
3 1 3
4 2 4
5 2 5
6 3 6
与你的问题类似。
代码的棘手部分是( mis - )使用MERGE
语句,以便能够从inserted
表中捕获列(包含新生成的IDENTITY
值)和充当行源的表。 OUTPUT
语句仅的INSERT
子句允许引用inserted
伪表,因此不能在此处使用。
答案 1 :(得分:1)
你提出的第二个建议不是绝对的方法。
我想你应该在单个事务中进行每个插入(可能在一个过程中)。如果您的ID是标识,则可以使用@@IDENTITY
获取最后插入的值并将其插入映射表中。
BEGIN TRAN
DECLARE @ID1 numeric, @ID2 numeric
INSERT INTO Request values (//insert values
SET @ID1=(SELECT @@IDENTITY)
INSERT INTO Service values (//insert values
SET @ID2=(SELECT @@IDENTITY)
INSERT INTO Mapping values (@ID1,@ID2);
COMMIT TRAN
否则,您可以使用 SELECT MAX(ID)WITH(UPDLOCK),这将阻止您的表在您的交易无法完成时插入其他记录。
BEGIN TRAN
DECLARE @ID1 numeric, @ID2 numeric
SET @ID2=(SELECT max(SId)+1 FROM Service WITH(UPDLOCK))
INSERT INTO Request values (@ID1,//other values
INSERT INTO Service values (@ID2,//other values
INSERT INTO Mapping values ((SELECT max(MId)+1 FROM Mapping),@ID1,@ID2);
COMMIT TRAN