Sql server 如何编写SQL对象(表、过程)部署脚本以避免由于相互依赖性而导致的错误?

Sql server 如何编写SQL对象(表、过程)部署脚本以避免由于相互依赖性而导致的错误?,sql-server,Sql Server,我有大量的sql server对象要批量部署。每个对象表、视图、过程等都在自己的文件中 问题是,许多对象具有相互依赖性,因此创建顺序很重要,否则会发生错误 目前,我正在使用一个dos批处理文件进行部署,该文件调用一个控制脚本,我已手动指定了脚本的执行顺序,如下所示: 批处理文件: SQLCMD -S %SERVER_NAME% -d %DATABASE_NAME% -i "DeployProcedures.sql" SQL脚本DeployProcedures.SQL: :r view1.sql

我有大量的sql server对象要批量部署。每个对象表、视图、过程等都在自己的文件中

问题是,许多对象具有相互依赖性,因此创建顺序很重要,否则会发生错误

目前,我正在使用一个dos批处理文件进行部署,该文件调用一个控制脚本,我已手动指定了脚本的执行顺序,如下所示:

批处理文件:

SQLCMD -S %SERVER_NAME% -d %DATABASE_NAME% -i "DeployProcedures.sql"
SQL脚本DeployProcedures.SQL:

:r view1.sql
:r view2.sql
:r view3.sql
etc
:r proc1.sql
:r proc2.sql
:r proc1.sql
etc
这是可行的,但必须不断更新这一点很麻烦

还有别的方法吗?我想我甚至会很乐意运行部署4次,在前3次迭代中使用抑制错误或不失败错误,然后在最后一次迭代中只启用终止错误

我更喜欢自己创作的东西,而不是商业产品,比如:


编辑:对一个问题投反对票,这个问题实际上是有人费心去写商业应用程序的问题——叹气。

sys.sql\u expression\u dependencies是你的朋友

例如:

-- Show all the things that all objects depend on
SELECT o.name AS [Object], o.[type] AS [ObjectType], t.name AS [DependsOn], t.type AS [DependentObjectType]
  FROM sys.objects o
       INNER JOIN sys.sql_expression_dependencies d ON o.object_id = d.referencing_id
       INNER JOIN sys.objects t ON d.referenced_id = t.object_id
 ORDER BY o.name, t.name

基本上,您可以根据从该查询中找到的依赖项生成按顺序运行脚本的文件。这将需要一些按摩为您的应用程序,但这应该是一个良好的开端。当然,您总是可以添加一个过滤器来限制特定类型的内容。几乎可以按任何顺序创建所有表。按这种顺序排列的视图、函数和存储过程有点棘手。。。视图尤其可能具有难以处理的递归依赖项,但递归CTE也可能在此处自动生成订单。

这看起来是一种粗糙但非常简单的处理方法:

主要摘录:

源代码管理中数据库对象的规则很简单:一个文件 以将要删除然后创建的对象命名的每个对象 对象可以使用Scriptio之类的工具提取现有对象 归档。加入一个小的文件组织,你就准备好了 办理登机手续:

        1.FUNCTIONS\
           1.FormatOrderNumber.sql
        2.VIEWS\
           1.OrdersWithTotals.sql
           1.SalesReport.sql
           2.OrdersPastDue.sql
        3.PROCS\
           1.AddItemToOrder.sql
           1.ValidateOrder.sql
           2.ProcessOrder.sql
请注意,数字前缀确保正确的执行顺序。 程序可以使用视图,而视图又可以使用函数。。。但是 通常不是相反。而且由于有少量的数据库对象 根据其他对象的不同,这些对象的前缀可以是“2”,而不是“1”

这些脚本的执行同样简单,并且可以完成 使用简单的批处理文件:

          FOR /R %%f IN (*.sql) DO (
          ECHO Running %%f
          OSQL -E -i "%%f" -n -b -d myDatabase -S myServer
        )
通过在源代码管理中设置脚本和批处理脚本,构建 您的数据库代码很容易从源代码管理和 单击“执行脚本”

这里概述了另一种可能的方法:

我将粘贴一个脚本,但文章中还有其他脚本值得查看

Here is a routine that shows you the soft dependency order of the objects in your database, and lists the external dependencies of any objects. (note that a lot of entities in a database aren’t classed as objects. )


IF object_id (N'DependencyOrder') IS NOT NULL

    DROP FUNCTION dbo.DependencyOrder

GO



CREATE FUNCTION dbo.DependencyOrder()

/*  

summary:   >

 This table-valued function is designed to give you the order in which

 database objects should be created in order for a build to succeed

 without errors. It uses the sys.sql_expression_dependencies table

 for the information on this.

 it actually only gives the level 1,,n so within the level the order

 is irrelevant so could, i suppose be done in parallel!

 It works by putting in successive passes, on each pass adding in objects

 who, if they refer to objects, only refer to those already in the table

 or whose parent object is already in the table. It goes on until no more

 objects can be added or it has run out of breath. If it does more than

 ten iterations it gives up because there must be a circular reference  

 (I think that's impossible)



Revisions:

 - Author: Phil Factor

   Version: 1.0

   Modification: First cut

   date: 3rd Sept 2015

 example:

     - code: Select * from dbo.DependencyOrder() order by theorder desc

returns:   >

a table, giving the order in which database objects must be built



*/

RETURNS @DependencyOrder TABLE 

  (TheSchema VARCHAR(120) null, TheName VARCHAR(120) NOT null, Object_id INT PRIMARY KEY, TheOrder INT NOT null,iterations INT null,ExternalDependency VARCHAR(2000) null )

AS

-- body of the function

BEGIN

DECLARE @ii INT,@EndlessLoop INT,@Rowcount INT

SELECT @ii=1, @EndlessLoop=10, @RowCount=1

WHILE @rowcount>0 AND @endlessLoop>0

       BEGIN

       ;WITH candidates  (object_ID, Parent_object_id) AS

              (SELECT sys.objects.Object_ID,sys.objects.parent_Object_id

              FROM sys.objects

              LEFT OUTER JOIN @DependencyOrder Dep --not in the dependency table already

              ON dep.Object_id = objects.object_id

              WHERE dep.Object_id IS NULL

              AND type NOT IN ('s', 'sq','it')

              )

       INSERT INTO @DependencyOrder  (TheSchema,TheName,Object_id,TheOrder)

       SELECT  object_schema_name(c.Object_ID),object_name(c.Object_id),c.object_id, @ii

       FROM candidates c   INNER JOIN @DependencyOrder parent

       ON c.Parent_object_ID= parent.Object_ID

       UNION

       SELECT  object_schema_name(Object_ID),object_name(Object_id),object_id, @ii

        FROM candidates c 

       WHERE  Parent_object_id=0

       AND object_id NOT IN (

       SELECT c.object_id  

        FROM candidates c

               INNER JOIN sys.sql_expression_dependencies

       ON object_ID=referencing_ID

       LEFT OUTER JOIN @DependencyOrder ReferedTo

       ON ReferedTo.object_id =referenced_ID

       WHERE ReferedTo.object_id IS NULL

       AND  referenced_id IS  NOT NULL--not a cross-database dependency

)

       SET @rowcount=@@rowcount

       SELECT @ii=@ii+1,@EndlessLoop=@EndlessLoop-1

       END 

       UPDATE  @dependencyOrder SET iterations= @ii-1

       UPDATE  @dependencyOrder  SET   ExternalDependency= ListOfDependencies

              FROM   

                 (SELECT Object_ID, STUFF(

                     (SELECT ', '+coalesce(referenced_server_name+'.','')

                     +coalesce(referenced_database_name+'.','')

                     +coalesce(referenced_schema_name+'.','')

                     +referenced_entity_name 

                     FROM sys.sql_expression_dependencies sed

                     WHERE sed.referencing_ID=externalRefs.object_ID

                     and  referenced_database_name IS NOT NULL AND is_ambiguous=0

                     FOR Xml PATH (''), ROOT('i'), TYPE).value('/i[1]', 'varchar(max)')

                     ,1,2,'') ListOfDependencies

                 FROM @dependencyOrder externalRefs



                )f

              INNER JOIN @dependencyOrder d ON f.object_id=d.Object_ID



RETURN

END

GO

我能找到的唯一方法是继续重新部署所有在循环中失败的对象,并在第一轮没有成功安装失败对象时停止。不是最优雅的解决方案…:在我看来,这是一种可以接受的方法,但我不知道忽略错误并继续的正确语法是什么。我认为从sys.sql_表达式_依赖项中导出所需的顺序是困难的。一旦你弄明白了这一点,这可能是一个非常重要的练习来实现它。我无法想象我是第一个遇到这个问题的人,肯定有一些现有的方法。