我有一个SQL脚本,每次客户端执行“数据库管理”功能时都必须运行。该脚本包括在客户端数据库上创建存储过程。其中一些客户端在运行脚本时可能已经拥有存储过程,而另一些客户端可能没有。我需要将丢失的存储过程添加到客户端数据库中,但无论我如何尝试改变T-SQL语法,我都得到了这个结果

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

我在创作作品之前读到过这种说法,但我不喜欢这样做。

IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'MyProc')
DROP PROCEDURE MyProc
GO

CREATE PROCEDURE MyProc
...

如何添加检查存储过程是否存在,如果存储过程不存在则创建它,如果存储过程存在则修改它?


当前回答

这里有一个方法和一些使用它的理由。编辑存储的proc并不是很漂亮,但是有利有弊……

更新:您还可以将整个调用包装在一个TRANSACTION中。在单个事务中包含多个存储过程,这些存储过程可以全部提交或全部回滚。在事务中封装的另一个优点是,只要其他SQL连接不使用READ UNCOMMITTED事务隔离级别,存储过程就始终存在!

1)避免将变更作为流程决策。我们的过程总是IF存在,然后创建。如果您执行相同的模式,假设新的PROC是所需的PROC,那么满足alters就有点困难,因为您将拥有If EXISTS ALTER ELSE CREATE。

2)你必须把CREATE/ALTER作为批处理中的第一个调用,这样你就不能在动态SQL之外的事务中包装一系列过程更新。基本上,如果您想运行整个过程更新堆栈或在不恢复DB备份的情况下将它们全部回滚,这是一种在单个批处理中完成所有工作的方法。

IF NOT EXISTS (select ss.name as SchemaName, sp.name as StoredProc 
    from sys.procedures sp
    join sys.schemas ss on sp.schema_id = ss.schema_id
    where ss.name = 'dbo' and sp.name = 'MyStoredProc')
BEGIN
    DECLARE @sql NVARCHAR(MAX)

    -- Not so aesthetically pleasing part. The actual proc definition is stored
    -- in our variable and then executed.
    SELECT @sql = 'CREATE PROCEDURE [dbo].[MyStoredProc]
(
@MyParam int
)
AS
SELECT @MyParam'
    EXEC sp_executesql @sql
END

其他回答

创建程序(如果不存在)结束

我知道你想“修改一个存在的过程,创建一个不存在的过程”,但我相信这样更简单:

删除该过程(如果它已经存在),然后 重新创建它。

是这样的:

IF OBJECT_ID('MyProcedure', 'P') IS NOT NULL
    DROP PROCEDURE MyProcedure
GO

CREATE PROCEDURE MyProcedure AS
BEGIN
    /* ..... */
END
GO

第二个参数告诉OBJECT_ID只查找object_type = 'P'的对象,这些对象是存储过程:

AF = Aggregate function (CLR) C = CHECK constraint D = DEFAULT (constraint or stand-alone) F = FOREIGN KEY constraint FN = SQL scalar function FS = Assembly (CLR) scalar-function FT = Assembly (CLR) table-valued function IF = SQL inline table-valued function IT = Internal table P = SQL Stored Procedure PC = Assembly (CLR) stored-procedure PG = Plan guide PK = PRIMARY KEY constraint R = Rule (old-style, stand-alone) RF = Replication-filter-procedure S = System base table SN = Synonym SO = Sequence object TF = SQL table-valued-function TR = Trigger

你可以通过以下途径获得完整的选项列表:

SELECT name 
FROM master..spt_values
WHERE type = 'O9T'

我意识到这已经被标记为已回答,但我们过去是这样做的:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND OBJECT_ID = OBJECT_ID('dbo.MyProc'))
   exec('CREATE PROCEDURE [dbo].[MyProc] AS BEGIN SET NOCOUNT ON; END')
GO

ALTER PROCEDURE [dbo].[MyProc] 
AS
  ....

只是为了避免手术失败。

除了来自@Geoff的回答之外,我还创建了一个简单的工具,它可以生成一个sql文件,其中包含存储过程、视图、函数和触发器的语句。

查看我的团。

我也犯了同样的错误。我知道这个线程已经死了,但我想设置另一个选项除了“匿名过程”。

我是这样解决的:

Check if the stored procedure exist: IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='my_procedure') BEGIN print 'exists' -- or watever you want END ELSE BEGIN print 'doesn''texists' -- or watever you want END However the "CREATE/ALTER PROCEDURE' must be the first statement in a query batch" is still there. I solved it like this: SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE -- view procedure function or anything you want ... I end up with this code: IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID('my_procedure')) BEGIN DROP PROCEDURE my_procedure END SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].my_procedure ...