如何将存储过程的结果返回到用于插入记录的选择语句
Posted
技术标签:
【中文标题】如何将存储过程的结果返回到用于插入记录的选择语句【英文标题】:How do I return the result of a stored procedure to a select statement that is being used to insert records 【发布时间】:2016-09-27 13:05:14 【问题描述】:我正在编写一个脚本来在软件更新后转换一些数据。我正在引入一个新表,需要将现有表中的数据提取到这个新表中。我需要从一个表中获取一个现有的 varchar(max) 字段,在另一个表中基于它创建一个父子记录,然后在另一个表中插入新父记录的标识。
所以它有点想看起来像这样
INSERT INTO NEWTABLE (val1, val2, val3)
SELECT
val1,
val2,
EXEC AStoredProc(val3) -- this obviosuly doesnt work
FROM EXISTINGTABLE
CREATE PROCEDURE AStoredProc
@Value nvarchar(max),
@NewID int OUTPUT
DECLARE @ParentID int
INSERT INTO AnotherTable ([Text], ParentNodeID)
VALUES ('',NULL)
SELECT @ParentID = SCOPE_IDENTITY()
INSERT INTO AnotherTable ([Text], ParentNodeID)
VALUES (@Value,@ParentID)
SELECT @ParentID
END
在上面的示例中,val1 和 val2 字段只是直接迁移到新表中。新表中的 val3 是一个 int 并且是从 AStoredProc 的结果插入的,它采用现有表的 varchar(max) val3 值在另一个表中创建几个记录并从它们返回新的父 ID,然后在新表中作为 val3 插入。
不用担心设计的原因,我怎样才能在存储过程中运行一些插入内容并将结果直接返回到外部 Select 语句?
【问题讨论】:
【参考方案1】:我能想到的两个选项是:
使用CURSOR
:
DECLARE @val1 datatype1,
@val2 datatype2,
@val3 NVARCHAR(MAX),
@ParentID INT;
DECLARE migrate CURSOR LOCAL STATIC
FOR SELECT et.val1, et.val2, et.val3
FROM EXISTINGTABLE et
WHERE NOT EXISTS (
SELECT *
FROM NEWTABLE nt
WHERE nt.val1 = et.val1
AND nt.val2 = et.val2
);
BEGIN TRY
OPEN migrate
FETCH NEXT
FROM migrate
INTO @val1, @val2, @val3;
WHILE (@@FETCH_STATUS <> 0)
BEGIN
BEGIN TRAN;
EXEC dbo.AStoredProc
@Value = @val3,
@NewID = @ParentID OUTPUT;
INSERT INTO NEWTABLE (val1, val2, val3)
VALUES (@val1, @val2, @ParentID);
COMMIT;
END;
CLOSE migrate;
DEALLOCATE migrate;
END TRY
BEGIN CATCH
ROLLBACK TRAN;
-- catch block stuff goes here
END CATCH;
至少在示例代码的存储过程中列出的第一个AnotherTable
(即生成@ParentID
值的表)中创建一个“临时”列,以保存新创建记录的关联。这将允许进行基于集合的操作,因为查询可以作为单独的步骤完成。如果EXISTINGTABLE
中已经有一个 IDENTITY 值/易于使用的 PK,则只需使用它,否则如果临时列是 UNIQUEIDENTIFIER
并使用 NEWID()
,则可以轻松创建一个新值。但假设目前是幸福的道路(即EXISTINGTABLE
有INT
PK),那么它会是这样的:
-- set up temporary association column
ALTER TABLE dbo.AnotherTable
ADD [TempAssociationID] INT NOT NULL;
BEGIN TRY
BEGIN TRAN;
-- populate initial "parent" records
INSERT INTO dbo.AnotherTable ([Text], [TempAssociationID])
SELECT '', et.PK_column
FROM dbo.EXISTINGTABLE et;
-- populate "child" records
INSERT INTO dbo.AnotherTable ([Text], [TempAssociationID], ParentNodeID)
SELECT et.val3, et.PK_column, anthr.ID_column AS [ParentNodeID]
FROM dbo.EXISTINGTABLE et
INNER JOIN dbo.AnotherTable anthr
ON anthr.[TempAssociationID] = et.PK_column
AND anthr.[ParentNodeID] IS NULL;
-- combine existing and secondary tables for "new" table
INSERT INTO dbo.NEWTABLE (val1, val2, val3)
SELECT et.val1, et.val2, anthr.ID_column AS [val3]
FROM dbo.EXISTINGTABLE et
INNER JOIN dbo.AnotherTable anthr
ON anthr.[TempAssociationID] = et.PK_column
AND anthr.[ParentNodeID] IS NULL;
COMMIT TRAN;
END TRY
BEGIN CATCH
ROLLBACK TRAN;
-- other catch block stuffs
END CATCH;
ALTER TABLE dbo.AnotherTable
DROP COLUMN [TempAssociationID];
【讨论】:
是的,我有点想他们会是我的选择。认为我将采用光标方法。有点希望它可以在一个容易回滚的事务中完成 @StewartAlan 可以...让我完成选项 2 ;-)。 @StewartAlan 请查看竞争选项#2 :)以上是关于如何将存储过程的结果返回到用于插入记录的选择语句的主要内容,如果未能解决你的问题,请参考以下文章
Oracle存储过程创建临时表,插入数据后,怎么返回临时表数据,并在asp.net中接收到datatable中
存储过程返回2个结果数据集 - 有没有办法只将第一个数据集插入变量但仍然显示第二个?