22

我意识到这是一个非常类似于Stop SSMS from scripting SPs using sp_executesql?

然而,他们似乎改变了 SSMS 2012 的行为。

如果您选择了“检查存在”选项,如下所示:

在此处输入图像描述

...它现在为即将创建的 proc 生成一个 IF NOT EXISTS,以及为前一个 drop proc 生成一个 IF EXISTS,如果像我通常做的那样,我选择 DROP and CREATE 选项:

在此处输入图像描述

这会强制它使用 sp_executesql 编写 CREATE 脚本。这是没有意义的,因为如果 DROP 刚刚删除了它,则不需要对 CREATE 进行 IF NOT EXISTS 检查。

似乎不可能有一个没有另一个。

有任何想法吗?

4

4 回答 4

9

如果没有动态 SQL,您将无法做到这一点,因为存储过程必须在其自己的批处理中。因此你不能说:

IF <some condition>
  <start a new batch>

将其保存在同一批次中的唯一方法是使用sp_executesql.

如果您要同时编写 and 脚本DROPCREATE只需在不检查对象存在的情况下执行此操作。这会给你:

DROP PROCEDURE ...;
GO
CREATE PROCEDURE ...;
GO

谁在乎是否DROP失败?(不应该,因为您只是根据它编写了脚本!)

如果您正在为另一个可能有该对象的系统编写脚本,您将在没有该对象时收到一条错误消息DROP,但CREATE仍然会发生,因此您可以忽略这些DROP错误。如果你真的想要,你可以手动包装DROP语句,TRY/CATCH但我认为没有必要。

如果您需要为很多程序执行此操作,或者如果您确实需要该过程不产生良性错误,我建议您放弃 Management Studio 的原始脚本选项并为此使用第 3 方工具。他们已经处理了许多您还没有遇到的问题,但会。我在博客上写过这个:

http://bertrandaaron.wordpress.com/2012/04/20/re-blog-the-cost-of-reinventing-the-wheel/

于 2012-05-16T14:55:00.800 回答
5

最接近此功能的是进入工具、选项、SQL Server 对象资源管理器、脚本,然后将检查对象存在设置为 false。

缺点是如果你这样做,那么即使对象不存在,drop 和 created 也将始终尝试 drop。理想的解决方案是允许您的脚本类似于以下示例的设置,用于创建视图、过程和用户​​定义的函数。

/****** Object:  View [dbo].[vEmployees]    Script Date: 9/14/2012 9:18:57 AM ******/
IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vEmployees]'))
DROP VIEW [dbo].[vEmployees]
GO

CREATE VIEW [dbo].[vEmployees]
AS
    SELECT DISTINCT
        Employees.EmployeeID,
        FirstName,
        LastName
    from
        Employees
            JOIN Sales on Employees.EmployeeID=Sales.EmployeeID
GO

简而言之,如果脚本引擎在检查对象是否存在时同时考虑删除和创建,则不需要将条件放在创建上。

于 2012-09-14T14:48:19.813 回答
1

我找到了解决这个问题的好方法。编写脚本时必须进行“两次通过”。在第一次通过时,选择检查存在和仅用于 DROP 脚本的选项。然后,在第二次通过时,取消选择 Check for Existence 选项并选择 CREATE 脚本。此外,使用附加到文件选项。然后在第二遍运行生成脚本时,取消选中“覆盖文件”选项。这仅在您为每个对象生成单独的文件时才有效。

于 2015-03-31T16:27:04.647 回答
0

我也为同样的问题而苦苦挣扎。如果您需要为整个数据库编写对象脚本,您可能需要考虑 ApexSQL 脚本。我尝试了几种工具,ApexSQL 完全按照我的需要编写了对象脚本。(如果对象存在,则删除。创建对象)。我相信它也可以从命令行工作。注意,它是共享软件;我只使用了评估版,因为我只需要它几次。

下面是一些配置后过程的输出示例。

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

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE dbo.myProcedure
AS
    select 1 as a
GO
于 2014-01-08T22:07:11.207 回答