如何在另一个插入存储过程期间调用一个插入存储过程并获取其返回的ID?

Posted

技术标签:

【中文标题】如何在另一个插入存储过程期间调用一个插入存储过程并获取其返回的ID?【英文标题】:How to call an insert stored procedure during another insert stored procedure and get its returned ID? 【发布时间】:2016-08-27 23:26:19 【问题描述】:

如果我的问题没有意义,我深表歉意。

所以我采用了一个使用 GUID 作为 PK 的数据库表,并且我已经对该数据库进行了规范化,并开始将现有数据库中的数据合并到新结构化的数据库中。 我有一个看起来像这样的原始表

create table #tmpMaterial
(
    ID int identity(1,1),
    MaterialID nvarchar(128),
    MaterialCategoryID nvarchar(128),
    MaterialTypeID nvarchar(128),
    MaterialSubTypeID nvarchar(128),
    MaterialDetail nvarchar(20),
    Description nvarchar(100),
    MaterialWidth numeric(10,2),
    MaterialLength int,
    MaterialSize nvarchar(20),
    PurchUnitOfMeasureID nvarchar(128),
    PurchaseItemQuantity int,
    SellUnitOfMeasureID nvarchar(128),
    SellItemQuantity int,
    NewPrice money,
    RemodPrice money,
    ServicePrice money,
    DefVendorID nvarchar(128),
    EnabledInd tinyint
)

数据的插入是这样的

insert into #tmpMaterial
select tmpM.MaterialID, tmpM.MaterialCategoryID,tmpM.MaterialTypeID, tmpM.MaterialSubTypeID, tmpM.MaterialDetail, tmpM.Description, tmpM.MaterialWidth, tmpM.MaterialLength, tmpM.MaterialSize,
tmpM.PurchUnitOfMeasureID, tmpM.PurchItemQuantity, tmpM.SellUnitOfMeasureID, tmpM.SellItemQuantity, tmpM.NewPrice, tmpM.RemodPrice, tmpM.ServicePrice, tmpM.DefVendorID, tmpM.EnabledInd
from Exovations.dbo.Material tmpM

所以这会将原始数据插入到临时表中,这个临时表就是我要查询的。 我有一个临时表,它是新创建的确切表,它是

create table #tmpMaterialFinal
(
    ID int identity(1,1),
    MaterialCategoryID int,
    MaterialTypeID int,
    MaterialSubTypeID int,
    CompanyID int,
    DimensionsID int,
    PurchaseUOMID int,
    SellUOMID int,
    VendorID int,
    MaterialDetail nvarchar(20),
    Description nvarchar(100),
    PurchaseItemQuantity int,
    NewPrice money,
    RemodelPrice money,
    ServicePrice money,
    IsActive bit
)

我正在查询#tmpMaterial 表并在此过程中进行一些连接以将该数据导入#tmpMaterialFinal 表。我预见的问题是,如果您查看#tmpMaterial 表,我有这三列

MaterialWidth numeric(10,2),
MaterialLength int,
MaterialSize nvarchar(20)

在我的#tmpMaterialFinal 中我有DimensionsID,这是它自己的名为Dimensions 的表,在Dimensions 表中我有3 列,一列用于宽度、长度和尺寸。

我需要做的是在向#tmpMaterialFinal 表中插入记录时,我需要调用一个名为usp_InsertDimensions 的存储过程并从#tmpMaterial 表中传递这3 个值,在插入#tmpMaterialFinal 表时我需要执行usp_InsertDimensions存储过程并获取其返回的 ID,以便我可以将该 ID 放入DimensionID 列中。

我的 usp_InsertDimensions 看起来像这样

CREATE PROCEDURE [dbo].[usp_InsertDimensions]
(
    @DimensionID int output,
    @DLength decimal(15,4),
    @DWidth decimal(15,4),
    @DHeight decimal(15,4)
)
AS
SET NOCOUNT OFF
SET TRANSACTION ISOLATION LEVEL READ COMMITTED

DECLARE @ERROR_SEVERITY int,
        @MESSAGE varchar(1000),
        @ERROR_NUMBER int,
        @ERROR_PROCEDURE nvarchar(200),
        @ERROR_LINE int,
        @ERROR_MESSAGE nvarchar(4000);

begin try
     insert into [Dimensions]
     (DLength, DWidth, DHeight)
     values
     (@DLength, @DWidth, @DHeight)
     set @DimensionID = SCOPE_IDENTITY()
end try
BEGIN CATCH
    SET @ERROR_SEVERITY = ISNULL(ERROR_SEVERITY(),'');
    SET @ERROR_NUMBER = ISNULL(ERROR_NUMBER(),'');
    SET @ERROR_PROCEDURE = ISNULL(ERROR_PROCEDURE(),''); 
    SET @ERROR_LINE = ISNULL(ERROR_LINE(),'');
    SET @ERROR_MESSAGE = ISNULL(ERROR_MESSAGE(),'');

    -- Test if the transaction is uncommittable.
    IF (XACT_STATE()) = -1
        BEGIN
            --PRINT N'The transaction is in an uncommittable state. Rolling back transaction.'
            ROLLBACK TRANSACTION;
        END;

    -- Test if the transaction is active and valid.
    IF (XACT_STATE()) = 1
        BEGIN
            --PRINT N'The transaction is committable. Committing transaction.'
            COMMIT TRANSACTION;   
        END;

    SET @MESSAGE = 'Error Occured in Stored Procedure ' + cast(@ERROR_PROCEDURE as varchar(200)) + 
                    '; Line Number ' + cast(@ERROR_LINE as varchar) + 
                    '; Message: [' + cast(@ERROR_NUMBER as varchar) + '] - '
                    + cast(@ERROR_MESSAGE as varchar(255))

    RAISERROR(@MESSAGE, @ERROR_SEVERITY, 1);
END CATCH;

关于实现这一目标的正确方法有什么想法吗?

【问题讨论】:

我相信对this question 的回答应该能让您启动并运行。 @KamilG.,我查看了您提供的链接,我了解正在执行的操作的概念,但现在我收到错误子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。 【参考方案1】:

这是您可以使用的一种方法:

    在您的第一个表 #tmpMaterial 上添加一个 DimensionId 字段

    生成 sql 语句以将维度插入Dimensions 表并将DimensionId 存储回#tmpMaterial 表中。像这样的东西应该可以工作(目前手头没有要测试的 MSSQL):

    select 'declare @d_id int; exec usp_InsertDimensions @d_id output, ' + cast(MaterialLength as varchar(100)) + ', ' + cast(MaterialWidth as varchar(100)) + ', ' + cast(MaterialSize as varchar(100)) + '; Update #tmpMaterial set DimensionId = @d_id where ID = ' + cast(ID as varchar(100)) + '; go;' from #tmpMaterial

这将为您提供插入维度并将其 ​​ID 存储回源表所需的所有语句。您也可以将所有这些语句连接到一个变量中,然后将它们作为动态 sql 执行,或者将这些语句存储在临时表中并分批执行。

从这里开始,插入到最终表中将很简单。

【讨论】:

哇,好混乱 @Chris OK,对于#tmpMaterial 中的每条记录,您需要: 1) 通过调用存储的过程在Dimensions 中插入一条记录 2) 存储dimensionId。上面的查询为表中的每条记录生成执行此操作所需的 SQL sn-ps。获得 sn-ps 后,执行它们会将维度 ID 存储回 #tmpMaterial 表中。

以上是关于如何在另一个插入存储过程期间调用一个插入存储过程并获取其返回的ID?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何避免并行执行存储过程?

MySQL将失败记录插入另一个表

如何在sql创建一条插入数据的存储过程

等待批量插入存储过程完成

如何在C#中调用的存储过程正确插入数据而不提供所有可选参数?

如何将存储过程的结果返回到用于插入记录的选择语句