我们目前有多个数据库,但希望将它们组合起来,而是使用架构将我们的域上下文分开。
在MS SQL Server 2008 R2中,如何将一个架构的所有内容批量重新放置到另一个架构中?
例如,我们在dbo
架构中创建的所有表,视图,过程,索引等... 现在都将存在于foo
架构中。
编辑:我想根据AaronBertrand的精彩评论进行澄清。这不是多租户的情况。我们的情况是内部工具插件是由没有将表合并到工具数据库中的开发人员隔离开发的。
我们目前有多个数据库,但希望将它们组合起来,而是使用架构将我们的域上下文分开。
在MS SQL Server 2008 R2中,如何将一个架构的所有内容批量重新放置到另一个架构中?
例如,我们在dbo
架构中创建的所有表,视图,过程,索引等... 现在都将存在于foo
架构中。
编辑:我想根据AaronBertrand的精彩评论进行澄清。这不是多租户的情况。我们的情况是内部工具插件是由没有将表合并到工具数据库中的开发人员隔离开发的。
Answers:
基本概念实际上非常简单:您可以从中生成脚本sys.objects
并sys.schemas
构建ALTER SCHEMA TRANSFER
语句。因此,例如,您在dbo
架构中有三个对象,并且想要将它们全部移动到blat
架构中:
Table: dbo.foo
Table: dbo.bar
View: dbo.vFooBar
如下代码:
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql += N'
ALTER SCHEMA blat TRANSFER dbo.' + QUOTENAME(o.name) + ';'
FROM sys.objects AS o
INNER JOIN sys.schemas AS s
ON o.[schema_id] = s.[schema_id]
WHERE s.name = N'dbo';
PRINT @sql;
-- EXEC sp_executesql @sql;
将产生以下脚本(但可能不按此顺序):
ALTER SCHEMA blat TRANSFER dbo.bar;
ALTER SCHEMA blat TRANSFER dbo.foo;
ALTER SCHEMA blat TRANSFER dbo.vFooBar;
(您可能需要添加额外的滤镜来离开了对象的dbo
模式,你不想要移动,离开了特定的对象类型(例如,也许您的所有功能都实用功能,并不需要移动),生成脚本按对象类型等排序)
但是,将您所有的对象移动到新架构中存在两个问题:
可能很多代码仍会引用这些对象,因为dbo.object
-除蛮力外,没有简单的方法来解决此问题。您可能dbo.
很容易找到所有出现的情况,但是这些情况也可能返回误报,例如EXEC dbo.sp_executesql
,dbo.
中的注释,对保留在dbo.
架构中的对象的真实引用等。
您的依赖关系可能会完全不合时宜,但我尚未对此进行全面测试。我确实知道在这种情况下:
CREATE SCHEMA blat AUTHORIZATION dbo;
GO
CREATE TABLE dbo.foo(a INT PRIMARY KEY);
CREATE TABLE dbo.bar(a INT FOREIGN KEY REFERENCES dbo.foo(a));
GO
CREATE PROCEDURE dbo.pX AS
BEGIN
SET NOCOUNT ON;
SELECT a FROM dbo.bar;
END
GO
CREATE VIEW dbo.vFooBar
AS
SELECT foo.a, bar.a AS barA
FROM dbo.foo
INNER JOIN dbo.bar
ON foo.a = bar.a;
GO
ALTER SCHEMA blat TRANSFER dbo.foo;
ALTER SCHEMA blat TRANSFER dbo.bar;
ALTER SCHEMA blat TRANSFER dbo.pX;
ALTER SCHEMA blat TRANSFER dbo.vFooBar;
实际上,外键迁移比我预期的要平稳得多(要注意的是,我正在比您测试的最新版本进行测试)。但是因为其中的代码blat.pX
仍然引用dbo.bar
,显然执行了该过程:
EXEC blat.pX;
将产生此错误:
消息208,级别16,状态1,过程pX
无效的对象名称'dbo.bar'。
和依赖项查询,例如:
SELECT * FROM sys.dm_sql_referenced_entities('blat.pX', N'OBJECT');
将产生此错误:
消息2020,级别16,状态1
为实体“ blat.pX”报告的依赖项可能未包括对所有列的引用。这是因为该实体引用了一个不存在的对象,或者是由于该实体中的一个或多个语句中的错误。重新运行查询之前,请确保实体中没有错误,并且该实体引用的所有对象都存在。
并查询视图:
SELECT a, barA FROM blat.vFooBar;
产生以下错误:
消息208,级别16,状态1,过程vFooBar
无效的对象名称“ dbo.foo”。
消息4413,级别16,状态1
由于绑定错误而无法使用视图或函数“ blat.vFoobar”。
因此,这可能涉及大量清理工作。修复所有对象引用之后,您可能需要重新编译所有模块并刷新新模式中的所有视图。您可以为此生成一个脚本,该脚本与上面的示例非常相似。