【问题标题】:SQL error: 'CREATE/ALTER PROCEDURE' must be the first statement in a query batchSQL 错误:'CREATE/ALTER PROCEDURE' 必须是查询批处理中的第一条语句
【发布时间】:2012-01-29 04:41:41
【问题描述】:

我正在运行 SQL 脚本,但出现错误:

'CREATE/ALTER PROCEDURE' 必须是查询中的第一条语句 批处理

这是我的代码:

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'myproc') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[myproc]

create PROCEDURE [dbo].[myproc]

AS
BEGIN
    select * from mytable
END
GO

我该如何解决?

【问题讨论】:

    标签: sql-server-2008 tsql


    【解决方案1】:

    以下列形式运行您的语句:

    IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'myproc') AND type in (N'P', N'PC'))
      DROP PROCEDURE [dbo].[myproc]
    GO
    create PROCEDURE [dbo].[myproc]
    AS
    BEGIN
        select * from mytable
    END
    GO
    

    注意DROP PROCEDURE 后面的GO 批处理分隔符

    【讨论】:

    • 还要注意,如果 GO 后跟分号,错误消息将持续存在。 (SQLSrv 显然将分号解释为 CREATE 之前的空语句)。这个让我难过一阵子。
    • @xr280xr 你说的对,VS是按照GO stmt分批脚本,但是分号不是GO的一部分
    • 我们可以补充一下,'Go' 语句必须单独一行吗?
    • GO 关键字是秘诀。在没有 GO 的情况下运行上面的脚本,你会遇到同样的错误。
    【解决方案2】:

    您收到的错误消息是正确的。您可以使用 GO 关键字终止批处理(并开始另一个批处理)。

    将 GO 放在您的 Create procedure 语句之前。 GO 语句必须单独一行。

    【讨论】:

    • 'GO 语句必须单独一行。'让它发挥作用的非常重要的部分。
    【解决方案3】:

    我通常希望按照您的要求做相反的事情。例如,如果用户自定义了一个程序,并且我不想丢失他们的更改,但我想为我的所有客户应用统一的更新脚本,我希望能够执行以下操作:

    if not exists ( select * from sys.objects 
                where name='myProc' and objectproperty(object_id,'IsProcedure')=1 )
    create proc myProc 
    as begin
      -- proc stmts here
    end
    go
    

    这种逻辑只允许我创建不存在的东西,但令我非常沮丧的是,SQL Server 也阻止了这种情况。

    我很容易解决这个问题,如下所示:

    if not exists ( select * from sys.objects 
                where name='myProc' and objectproperty(object_id,'IsProcedure')=1 )
    exec('create proc myProc 
    as begin
      -- proc stmts here
      declare @object int = 0
    end')
    go
    

    通过将 create proc 命令作为字符串传递并将其放在 exec 语句中,我们绕过了阻止人们首先执行此操作的愚蠢规则。

    【讨论】:

      【解决方案4】:

      添加以下语句后,我的问题就消失了:

      SET ANSI_NULLS ON
      GO
      
      SET QUOTED_IDENTIFIER ON
      GO
      

      【讨论】:

      • 修复不一定是 ansi_null = on 和quoted_identifier = on,而是分隔脚本执行的 go
      【解决方案5】:

      您可能想尝试在另一个数据库中创建存储过程,而不是在当前上下文中创建它。

      设置@myScript = 'exec'+ QUOTENAME(@DBName) + '..sp_executesql N''create PROCEDURE [dbo].[myproc] 作为 开始 从 mytable 中选择 * 结尾''' 执行(@myScript)

      【讨论】:

        【解决方案6】:
        DECLARE @rn INT = 1, @dbname varchar(MAX) = '';
        
        DECLARE @myScript varchar(MAX) = '';
        WHILE @DBName IS NOT NULL 
        BEGIN
        
        
         SET @DBName = (SELECT name FROM (SELECT name, ROW_NUMBER() OVER (ORDER BY name) rn 
                FROM sys.databases WHERE name  IN ('RBAC','sakila')) t WHERE rn = @rn);
            
        set @myScript = 'exec '+ QUOTENAME(@DBName) + '..sp_executesql N''Alter PROCEDURE [dbo].[myproc]
        AS
        BEGIN
            select  765
        END'''
        execute(@myScript)
        SET @rn = @rn + 1;
        END;
        

        【讨论】:

        • edit您的回答解释为什么以及如何解决问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多