1

这是场景:

我有桌子Request(RId)、桌子Service(SId)和桌子Mapping(MId)

现在首先将请求生成到请求表中。然后创建其相关的 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 并插入 DB 并获取最后 5 个服务 Id 并通过 while 循环执行映射表的所有条目。意味着我只需要进入后端一次,但是如果任何其他人为他/她的请求插入了服务,我会得到错误的 ID 并且会错误地进行映射。

有没有更好的方法来做到这一点?

4

2 回答 2

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

这与您在问题中的内容相似。

代码的棘手部分是(错误地)使用该MERGE语句,以便能够从inserted表(包含新生成的IDENTITY值)和充当行源的表中捕获列。该语句的OUTPUT子句允许引用伪表,所以不能在这里使用。INSERTinserted

于 2013-04-12T07:05:44.523 回答
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
于 2013-04-12T06:31:52.447 回答