Sql server 如何编写SQL对象(表、过程)部署脚本以避免由于相互依赖性而导致的错误?
我有大量的sql server对象要批量部署。每个对象表、视图、过程等都在自己的文件中 问题是,许多对象具有相互依赖性,因此创建顺序很重要,否则会发生错误 目前,我正在使用一个dos批处理文件进行部署,该文件调用一个控制脚本,我已手动指定了脚本的执行顺序,如下所示: 批处理文件: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
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_表达式_依赖项中导出所需的顺序是困难的。一旦你弄明白了这一点,这可能是一个非常重要的练习来实现它。我无法想象我是第一个遇到这个问题的人,肯定有一些现有的方法。