你在SQL Server中做什么来创build或修改?

今年是2009年,SQL Server没有CREATE OR ALTER / REPLACE。 这是我所做的。

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'SynchronizeRemoteCatalog' AND ROUTINE_SCHEMA = 'dbo' AND ROUTINE_TYPE = 'PROCEDURE') EXEC ('DROP PROCEDURE dbo.SynchronizeRemoteCatalog') CREATE PROCEDURE dbo.SynchronizeRemoteCatalog AS BEGIN -- body END 

对于触发器,您必须依靠专有系统视图。

这是最受欢迎的习俗吗?

编辑:正如n8wrlbuild议, 官方的话表明,这个function不是一个高优先级。 因此,这个问题。

是的,这就是我所有的构build脚本的样子。 最后,我还设置了权限。

本文在删除SQL Server中的对象时会丢失权限。

  • 提示'N'技巧 – T-SQL – 创build或更改存储过程的一种方法

所以这里是保留权限的方法:

 IF OBJECT_ID('spCallSomething') IS NULL EXEC('CREATE PROCEDURE spCallSomething AS SET NOCOUNT ON;') GO ALTER PROCEDURE spCallSomething ... --instead of DROP/CREATE 

也适用于函数,只需用上面代码中的FUNCTION代替PROCEDURE

考虑这样做的另一个原因是容忍失败。 假设你的DROP成功了,但是你的CREATE失败 – 你以一个破损的DB结束。 使用ALTER方法,你将会得到一个老版本的对象。

今年是2009年,SQL Server没有CREATE OR ALTER / REPLACE。

今年是2016年,现在在SQL Server 2016 RTM中有DIE( Drop If Exists ),而CREATE OR ALTER (在2016 SP1中引入)。

采取Drop If Exists首先Drop If Exists需要重新申请这种方法权限的警告仍然适用。 示例语法是

 DROP PROCEDURE IF EXISTS dbo.SynchronizeRemoteCatalog GO CREATE PROCEDURE dbo.SynchronizeRemoteCatalog AS BEGIN BODY: END GO /*TODO: Reapply permissions*/ 

CREATE OR ALTER保留权限。 示例语法是

  CREATE OR ALTER PROCEDURE dbo.SynchronizeRemoteCatalog AS BEGIN BODY: END 

相应的MSSQL Tiger Team博客文章解释道

CREATE OR ALTER可用于可编程性对象,例如:

  • stored procedures(包括本地编译)
  • function(Transact-SQL,包括本机编译)
  • TRIGGERS
  • VIEWS

但不能用于:

  • 需要存储的对象(表,索引和索引视图)
  • CLR用户定义的函数
  • 弃用的可编程性对象(RULE和DEFAULT)
  • 非可编程性对象(如CREATE ASSEMBLY,CREATE TABLE或CREATE-SCHEMA)。 在这些对象上,CREATE和ALTER的语法与语法和可用性透视图非常不同。

每次开发者写入IF EXISTS(...) DROP一个印章的小狗被杵在一起。 您应该确切地知道数据库中的内容,并且升级脚本应根据应用程序模式的当前版本(适用于版本控制和数据库)进行适当的CREATe或ALTER升级。

我们遇到了需要更新远程站点的情况,但是我们没有DROP权限。 到目前为止,我们一直在使用SSMS 2008 R2内置的“DROP CREATE”脚本,但现在我们需要改变。 我们创build了三个模板,当我们需要更新存储过程或函数时,我们将其放在适当的ALTER脚本之上:

 —- Stored Procedure IF OBJECT_ID('[dbo].[<Name_Of_Routine, , >]') IS NULL EXEC('CREATE PROCEDURE [dbo].[<Name_Of_Routine, , >] AS SET NOCOUNT ON;') EXEC('GRANT EXECUTE ON [<Name_Of_Routine, , >] TO Public AS dbo;') GO —- Scalar Function IF OBJECT_ID('[dbo].[<Name_Of_Routine, , >]') IS NULL EXEC('CREATE FUNCTION [dbo].[<Name_Of_Routine, , >] (@i INT) RETURNS INT AS BEGIN RETURN 0 END;') EXEC('GRANT EXECUTE ON [<Name_Of_Routine, , >] TO Public AS dbo;') GO —- Table-based Function IF OBJECT_ID('[dbo].[<Name_Of_Routine, , >]') IS NULL EXEC('CREATE FUNCTION [dbo].[<Name_Of_Routine, , >] (@i INT) RETURNS @O TABLE(i INT) AS BEGIN INSERT INTO @O SELECT 0 RETURN END;') GO 

在每个CREATE(表函数不能被分配权限)后,任何特殊的权限都会被脚本化。 之后,ALTER不会更改它,如果它们添加或修改权限,它们将保留。 这样做,复制函数或存储过程的名称是一件容易的事情,并使用模板参数replace来自动完成这些脚本。

现在,我希望微软的好人可以将它添加到他们的“Script ___ as”列表中,或者让我们能够创build自己的脚本,

您可能想要在SQL Server反馈条目后面添加一些权限: https : //connect.microsoft.com/SQLServer/feedback/details/344991/create-or-alter-statement 。 它似乎是less数仍然可以公开访问的国家之一,他们表示,“已经开始对此进行可行性审查,以决定我们是否可以在不久的将来发布这个报告”。 声音越多,发生的可能性就越大!

(更新:现在也使用下面的代码触发器和视图)

 -- Triggers IF OBJECT_ID('[dbo].[<Name_Of_Trigger, , >]') IS NULL -- Check if Trigger Exists EXEC('CREATE TRIGGER [dbo].[<Name_Of_Trigger, , >] ON [<Name_Of_Table, , >] AFTER UPDATE AS SET NOCOUNT ON;') -- Create dummy/empty SP GO -- Views IF OBJECT_ID('[dbo].[<Name_Of_View, , >]') IS NULL -- Check if View Exists EXEC('CREATE VIEW [dbo].[<Name_Of_View, , >] AS SELECT 1;') -- Create dummy/empty View GO 

我会在DROP之前使用OBJECT_ID(...) IS NOT NULL

对象标识符必须是唯一的,所以它不需要使用系统表就可以工作:

 CREATE TRIGGER dbo.ExistingTable ON dbo.AnotherTable FOR UPDATE AS SET NOCOUNT ON GO 

 Msg 2714, Level 16, State 2, Procedure MetaClass, Line 3 There is already an object named ExistingTable ' in the database. 

我通常使用ALTER是因为我们如何处理源代码控制等

基本上是这样做的,是的。 我只是想知道你是否有特殊的理由来使用“EXEC”方法:

 IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'SynchronizeRemoteCatalog' AND ROUTINE_SCHEMA = 'dbo' AND ROUTINE_TYPE = 'PROCEDURE') EXEC ('DROP PROCEDURE dbo.SynchronizeRemoteCatalog') 

为什么不只是:

 IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'SynchronizeRemoteCatalog' AND ROUTINE_SCHEMA = 'dbo' AND ROUTINE_TYPE = 'PROCEDURE') DROP PROCEDURE dbo.SynchronizeRemoteCatalog 

???

对于触发器,有sys.triggers 。 这些是“sys”模式下的系统目录视图 – 不是严格的或直接的表。

渣子

我总是alter我的对象,因为drop是非常糟糕的做法,如果一个对象无法创build(24/7分贝!),以及其他海报提到的关于nuking权限的问题,可能会使数据库处于不良状态。

像Sublime,Atom和VS Code这样的编辑器可以让你制作代码片段作为模板,以便快速创build你的骨架脚本。 SQL 2016现在终于支持DROP IF EXISTS构造了,但是它仍然从错误的方向接近 – 所有东西都是一个drop/create而不是在遥远的过去create一次,然后alter 。 此外,我试图使我的标题尽可能短的工作,所以我没有比create proc dbo.myproc as create存根( create proc dbo.myproc as

浏览次数:

 if objectproperty(object_id('dbo.myview'), 'IsView') is null begin exec('create view dbo.myview as select 1 c') end go alter view dbo.myview as -- select * -- from table go 

特效:

 if objectproperty(object_id('dbo.myproc'), 'IsProcedure') is null begin exec('create proc dbo.myproc as') end go alter procedure dbo.myproc as set nocount on -- Add the stored proc contents here... go 

UDF(标量):

 if objectproperty(object_id('dbo.myudf'), 'IsScalarFunction') is null begin exec('create function dbo.myudf returns int as begin return null end') end go alter function dbo.myudf(@s varchar(100)) returns int as begin -- return len(@s) end go 

UDF(表格):

 if objectproperty(object_id('dbo.myudf'), 'IsTableFunction') is null begin exec('create function dbo.myudf returns @t table(x int) as begin return end') end go alter function dbo.myudf(@s varchar(100)) returns @result table ( -- Columns returned by the function id int identity(1, 1) primary key not null ,result varchar(100) null ) begin return end go 

看起来像是一段时间了: 链接文本

我的典型脚本:

 IF EXISTS (SELECT name FROM sysobjects WHERE name = 'ig_InsertDealer' AND type = 'P') DROP PROC dbo.ig_InsertDealer GO CREATE PROCEDURE dbo.ig_InsertDealer ... GO GRANT EXECUTE ON dbo.ig_InsertDealer TO ... GO 

我将根据上下文使用:初始构build或主要重构脚本将使用check / drop / create,纯维护脚本使用alter。

我有一个模板,它允许多次执行脚本没有错误。

 IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[aaa_test]') AND type in (N'P', N'PC')) EXEC('CREATE PROCEDURE aaa_test AS') EXEC('GRANT EXECUTE ON aaa_test TO someone') GO ALTER PROCEDURE aaa_test @PAR1 INT, @PAR2 INT=0 AS BEGIN SELECT @PAR1 AS Par1, CASE @PAR2 WHEN 0 THEN 'Default' ELSE 'Other' END AS Par2 END GO 

执行:

 EXEC aaa_test 1 EXEC aaa_test 1,5 

你不应该放弃一个对象。 丢弃物体有两个问题:

1)如果CREATE失败,则不再有对象。 (您可以使用交易来避免这种情况,代价是很多样板代码)

2)如果您没有明确地重新创build对象,则会丢失对象的权限。


我更喜欢在“如果不存在”的条件下创build一个空白对象,然后使用ALTER,并为此写了一些帮助程序。

今年是2017年,SQL Server有CREATE OR ALTER

SQL Server 2016 SP1和SQL Server vNext具有新的T-SQL语言语句 – CREATE [OR ALTER] for:

  • STOREDPROCEDURES
  • function
  • TRIGGERS
  • VIEWS

https://blogs.msdn.microsoft.com/sqlserverstorageengine/2016/11/17/create-or-alter-another-great-language-enhancement-in-sql-server-2016-sp1/

我更喜欢CREATE-ALTER方法(不是语法),而不是DROP-CREATE ,原因有二:

  • 权限(使用DROP-CREATE你必须重新创build它们)
  • object_id(改变对象不会改变它)

示例DROP-CREATE

 --Initial creation: CREATE PROCEDURE dbo.my_proc AS SELECT * FROM dbo.a WHERE i < 10; GO SELECT OBJECT_ID('dbo.my_proc'); GO -- Recreating DROP PROCEDURE IF EXISTS dbo.my_proc; GO CREATE PROCEDURE dbo.my_proc AS -- some meaningless comment SELECT * FROM dbo.a WHERE i < 10; GO SELECT OBJECT_ID('dbo.my_proc'); GO 

DB小提琴

正如我们所看到的, object_id已经改变了。

示例2: CREATE-ALTER

 -- Initial creation CREATE PROCEDURE dbo.my_proc2 AS SELECT * FROM dbo.a WHERE i < 10; GO SELECT OBJECT_ID('dbo.my_proc2'); GO -- Altering CREATE OR ALTER PROCEDURE dbo.my_proc2 AS -- some meaningless comment SELECT * FROM dbo.a WHERE i < 10; GO SELECT OBJECT_ID('dbo.my_proc2'); GO 

DB小提琴

在这种情况下, object_id保持不变。


示例场景,这可能会导致一些问题。 假设我们使用SQL Server 2016查询存储并强制为存储过程使用特定的查询计划。

DROP-CREATE

 USE T1; GO -- make sure that Query Store is READ_WRITE IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[a]') AND type in (N'U')) BEGIN CREATE TABLE [dbo].[a]( [i] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY, [g] [uniqueidentifier] NULL, [z] VARCHAR(10) ); END GO -- populate table (15k records) INSERT INTO dbo.a(g, z) SELECT NEWID(), number FROM (SELECT CAST([key] AS INT) AS number FROM OPENJSON( '[1' + REPLICATE(',1',3000-1)+']') ) AS num GO 5 -- initial creation CREATE PROCEDURE dbo.my_proc AS SELECT * FROM dbo.a WHERE z LIKE '12%' AND 1 = (SELECT 1); GO -- Clustered Index Scan EXEC dbo.my_proc; EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; GO --dc1 -- creating index CREATE NONCLUSTERED INDEX IX_dbo_a_z ON dbo.a([z] ASC) INCLUDE ([i], [g]); GO -- index seek EXEC dbo.my_proc; EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; -- forcing plan GUI, clustered scan -- dc3 EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; -- dc4 -- Clustered Index Scan EXEC dbo.my_proc; EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; -- dc5 /* MAIN PART - DROP - RECREATE */ DROP PROCEDURE IF EXISTS dbo.my_proc; GO CREATE PROCEDURE dbo.my_proc AS -- some meaningless comment added by developer SELECT * FROM dbo.a WHERE z LIKE '12%' AND 1 = (SELECT 1); GO /* MAIN PART END */ -- Index Seek EXEC dbo.my_proc; EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; -- object_id in query store is NULL -- is_forced_plan flag is ignored !!! 

第一次执行:
DC1

添加索引并执行: 在这里输入图像说明

强制计划: 在这里输入图像说明 在这里输入图像说明

另一个执行: 在这里输入图像说明

DROP-CREATE在这里输入图像说明


创build – 修改

 USE T2; GO -- make sure that Query Store is READ_WRITE IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[a]') AND type in (N'U')) BEGIN CREATE TABLE [dbo].[a]( [i] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY, [g] [uniqueidentifier] NULL, [z] VARCHAR(10) ); END GO -- populate table (15k records) INSERT INTO dbo.a(g, z) SELECT NEWID(), number FROM (SELECT CAST([key] AS INT) AS number FROM OPENJSON( '[1' + REPLICATE(',1',3000-1)+']') ) AS num GO 5 -- initial creation CREATE PROCEDURE dbo.my_proc AS SELECT * FROM dbo.a WHERE z LIKE '12%' AND 1 = (SELECT 1); GO -- Clustered Index Scan EXEC dbo.my_proc; EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; -- ca1 GO -- creating index CREATE NONCLUSTERED INDEX IX_dbo_a_z ON dbo.a([z] ASC) INCLUDE ([i], [g]); GO -- index seek EXEC dbo.my_proc; EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; --ca2 -- forcing plan GUI --ca3 EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; --ca4 -- Clustered Index Scan EXEC dbo.my_proc; EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; --ca5 GO /* MAIN PART - CREATE-ALTER */ CREATE OR ALTER PROCEDURE dbo.my_proc AS -- some meaningless comment added by developer SELECT * FROM dbo.a WHERE z LIKE '12%' AND 1 = (SELECT 1); GO /* MAIN PART END */ -- Clustered Index Scan EXEC dbo.my_proc; EXEC sp_query_store_flush_db; SELECT qsq.query_id, qsq.query_text_id, qsq.context_settings_id, qsq.[object_id], OBJECT_NAME(qsq.[object_id]) AS [object_name], qsp.is_forced_plan, qsqt.query_sql_text, qsrs.count_executions, CAST(qsp.query_plan AS XbML) AS sql_query_plan FROM sys.query_store_query qsq JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id JOIN sys.query_store_plan qsp ON qsq.query_id= qsp.query_id JOIN sys.query_store_runtime_stats qsrs ON qsrs.plan_id = qsp.plan_id WHERE query_sql_text LIKE '%dbo.a%' AND qsq.[object_id] <> 0 ORDER BY qsq.query_id; -- is_forced_plan is valid 

第一次执行:
在这里输入图像说明

添加索引并执行: 在这里输入图像说明

强制计划: 在这里输入图像说明 在这里输入图像说明

另一个执行: 在这里输入图像说明

CREATE-ALTER在这里输入图像说明

结果

随着下降创build我们失去了强制计划。

只是对我以前的答复 。

我更喜欢使用CREATE-ALTER DROP-CREATE另一个原因。 这可能导致丢失关于对象的特定属性。 例如ExecIsStartup

 USE master GO CREATE TABLE dbo.silly_logging(id INT IDENTITY(1,1) PRIMARY KEY ,created_date DATETIME DEFAULT GETDATE() ,comment VARCHAR(100)); GO CREATE PROCEDURE dbo.my_procedure AS INSERT INTO dbo.silly_logging(comment) VALUES ('SQL Server Startup'); GO -- mark procedure to start at SQL Server instance startup EXEC sp_procoption @ProcName = 'dbo.my_procedure' , @OptionName = 'startup' , @OptionValue = 'on'; SELECT name, create_date, modify_date, is_auto_executed FROM master.sys.procedures WHERE is_auto_executed = 1; --name create_date modify_date is_auto_executed --my_procedure 2017-07-28 06:36:21.743 2017-07-28 06:36:24.513 1 

现在让我们假设有人想用DROP-CREATE更新这个过程:

 DROP PROCEDURE dbo.my_procedure; GO CREATE PROCEDURE dbo.my_procedure AS -- adding meaningless comment INSERT INTO dbo.silly_logging(comment) VALUES ('SQL Server Startup'); GO SELECT name, create_date, modify_date, is_auto_executed FROM master.sys.procedures WHERE is_auto_executed = 1; -- empty 

如果你没有意识到这一点,或者你不检查,最终的程序将不会启动。