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

40

我正在运行一个 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

我该如何解决这个问题?

7个回答

56

请按照以下形式运行您的语句:

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批处理分隔符。


12
请注意,如果GO后面跟着一个分号,错误消息将继续存在。(显然,SQLSrv将分号解释为在CREATE之前的空语句)。这一点曾经困扰了我一段时间。 - kmote
@xr280xr 你是对的,VS会根据GO语句将脚本分成批处理,但分号不是GO的一部分。 - Oleg Dok
我们可以补充一下,'Go'语句必须单独占一行吗? - Nate
GO关键字是秘密武器。如果不使用GO运行您的脚本,将会遇到相同的错误。 - Micah Epps

32

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

在Create过程语句之前加入GO。GO语句必须单独占一行。


2
GO语句必须单独占一行。这是使其正常工作的非常重要的部分。 - Nate

13

通常情况下,我希望做与你所提问的相反的事情。例如,如果用户已经自定义了一个过程,并且我不想失去他们的更改,但是我想为所有客户应用统一的更新脚本,那么我希望能够像以下这样做:

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

通过将创建存储过程的命令作为字符串传递并放在执行语句中,我们规避了阻止首先执行此操作的愚蠢规则。


9

在我添加以下语句后,我的问题得到了解决:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

3
解决方法并不一定是将 ansi_null = on 和 quoted_identifier = on,而是使用分隔脚本执行的 go 命令。 - Onga Leo-Yoda Vellem

4

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

set @myScript = 'exec '+ QUOTENAME(@DBName) + '..sp_executesql N''create PROCEDURE [dbo].[myproc]
AS
BEGIN
    select * from mytable
END'''
execute(@myScript)

0
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;

1
请[编辑]您的答案,以解释它是如何解决问题的以及为什么这样做。 - guntbert

0
尝试将“GO”键放在过程查询的开头。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接