【问题标题】:A nested INSERT, UPDATE, DELETE, or MERGE statement is not allowed in a SELECT statementSELECT 语句中不允许嵌套的 INSERT、UPDATE、DELETE 或 MERGE 语句
【发布时间】:2017-05-12 13:50:02
【问题描述】:

我想插入一条记录,然后用存储过程返回该记录的详细信息:

USE 
TEST
GO

CREATE PROCEDURE AddProject(
    -- In
    @_title NVARCHAR(200),
    @_description NVARCHAR(MAX),
    -- Out
    @Title NVARCHAR(200) OUT,
    @Description NVARCHAR(MAX) OUT)
AS
BEGIN
    SELECT 
        [ProjectsTable.ProjectID], 
        [Title], 
        [Description]
    FROM 
        (INSERT INTO [Projects] ("Title", "Description")
         OUTPUT inserted.ProjectID
         VALUES (@_title, @_description)) ProjectsTable
END

我收到此错误,我做错了什么?

消息 10729,级别 15,状态 1,过程 AddProject,第 31 行
SELECT 语句中不允许嵌套的 INSERT、UPDATE、DELETE 或 MERGE 语句不是 INSERT 语句的行的直接源。

感谢回答:


程序最终是这样的:

USE 
    TEST
GO
    CREATE PROCEDURE AddProject(   

        -- In    
        @_title NVARCHAR(200),
        @_description NVARCHAR(MAX),    
        -- Out    
        @ProjectID INT OUT,
        @Title NVARCHAR(200) OUT,
        @Description NVARCHAR(MAX) OUT

    )
    AS
    BEGIN    

        BEGIN TRAN  

            INSERT INTO     
                [Projects]    
                    ("Title", "Description")
                VALUES    
                    (@_title, @_description)                

            SET @ProjectID = SCOPE_IDENTITY();

            SELECT 
                @Title = [Title], 
                @Description = [Description]                
            FROM 
                [Projects] 
            WHERE 
                [Projects].[ProjectID] = @ProjectID         

        COMMIT

    END

我这样称呼它:

Declare @ProjectID as INT
Declare @Title as NVARCHAR(200)
Declare @Description as NVARCHAR(MAX)

EXEC AddProject "Test project", "A test project", @ProjectID output, @Title output, @Description output

SELECT @ProjectID, @Title, @Description

【问题讨论】:

  • 返回您传入的相同数据的目的是什么?
  • 先插入,再获取ID的SCOPE_IDENTITY(),再返回Select语句。但我同意@George2.0Hope。
  • @George2.0Hope - 注意从 INSERT 的 OUTPUT 中获取的额外 ProjectID
  • @Hybris95 为您提供了正确的解决方案,令人困惑的是您的 SPROC 声明没有 ProjectID 的输出声明(或者像 Hybris95 或 WEI_DBA 我会推荐 SCOPE_IDENTITY()).. . 但是,当我执行此操作时,我将其包装在事务中并返回 @@ERROR;因为检索 ID 很重要,但如果它失败了要优雅地处理它。

标签: sql-server stored-procedures


【解决方案1】:

只需使用最新插入的标识即可从您的表中恢复标题和描述。

CREATE PROCEDURE AddProject(
    -- In
    @_title NVARCHAR(200),
    @_description NVARCHAR(MAX),
    -- Out
    @Title NVARCHAR(200) OUT,
    @Description NVARCHAR(MAX) OUT,
    @ProjectID INT OUT)
AS
BEGIN
    BEGIN TRAN
        INSERT INTO [Projects] (@_title, @_description);
        SET @ProjectID = SCOPE_INDENTITY();
        SELECT @Title = [Title], @Description = [Description] FROM [Projects] WHERE [Projects.ProjectID] = @ProjectID;
    COMMIT
END

注意新的 ProjectID OUT 参数

SCOPE_IDENTITY

【讨论】:

  • 哈,好点,我错过了那部分。使用 OUTPUT 关键字怎么样...这个问题是我可能需要的一个示例,但我可能需要使用 INSERT 的输出,因为我可能有多个插入
  • 您可以根据需要多次重复事务,SCOPE_IDENTITY 将为您提供当前上下文中最新创建的身份。我会将文档链接到它(查看)
  • 谢谢老兄。备查。你知道使用 OUTPUT 关键字查询的样子吗?
  • 不,但我显然不建议使用它。交易中的隔离是我能给你的最佳选择
  • 最后一件事。您为获得 2 个单独的 Title 和 Description 属性所做的 2 个选择。可以将其捆绑到一个选择中返回两列吗?
【解决方案2】:
CREATE PROCEDURE AddProject(
    -- In
    @_title NVARCHAR(200),
    @_description NVARCHAR(MAX),
    -- Out
    @Title NVARCHAR(200) OUT,
    @Description NVARCHAR(MAX) OUT,
    @ProjectID INT OUT,
    @err INT OUT)
AS
BEGIN
    BEGIN TRAN
        INSERT INTO [Projects] (@_title, @_description);
        SET @ProjectID = SCOPE_INDENTITY();
        SET @Title = (SELECT [Title] FROM [Projects] WHERE [Projects.ProjectID] = @ProjectID);
        SET @Description = (SELECT [Description] FROM [Projects] WHERE [Projects.ProjectID] = @ProjectID);
        SELECT @err = @@ERROR IF @err <> 0 BEGIN ROLLBACK TRANSACTION RETURN @err END
    COMMIT
END

【讨论】:

  • 如果出现错误,我建议使用 TRY CATCH 块
  • @Hybris95 我想这取决于您是想在 DBA 级别还是代码级别处理错误,是吗?
  • 无论如何,如果发生错误,考虑到它只能是 INSERT,它会自动回滚,所以让错误发生并在应用程序级别进行管理
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
相关资源
最近更新 更多