Tom*_*Tom 6 sql-server collation sql-server-2012 contained-database except
将数据库更改为部分包含时,出现以下错误:
无法解决 EXCEPT 操作中“Latin1_General_CI_AS”和“Latin1_General_100_CI_AS_KS_WS_SC”之间的排序规则冲突。
在编译 > 对象期间,过程“RSExecRole.DeleteExtensionModuleDDL”中遇到错误。数据库“VeeamOne”的包含选项已更改,或者该对象存在于模型 db 中并且用户尝试创建新的包含数据库。ALTER DATABASE 语句失败。无法更改数据库“VeeamOne”的包含选项,因为在验证 SQL 模块期间遇到编译错误。请参阅以前的错误。ALTER DATABASE 语句失败。(.Net SqlClient 数据提供程序)
我认为这是报告的对象来自 SSRS。但是,我正在更改排序规则的 DB 是一个完全独立的应用程序。
有没有人对如何解决这个问题有任何建议?
================================================== ====================== 好的,这是 proc 的代码,但不确定它是什么导致它无法被包含
USE [VeeamOne]
GO
/****** Object: StoredProcedure [reporter].[DeleteExtensionModuleDDL] Script Date: 02/12/2015 12:06:19 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [reporter].[DeleteExtensionModuleDDL]
@EMID int
AS
BEGIN
SET NOCOUNT ON;
declare @Debug bit;
set @Debug = 0;
declare @Emulate bit;
set @Emulate = 0;
declare @reportPackDestructorFunctionName nvarchar(max)
exec @reportPackDestructorFunctionName = [reporter].GenerateExtensionModuleDestructorName @EMID
if exists(select * from sys.objects where (object_id = OBJECT_ID(@reportPackDestructorFunctionName) and type in (N'P', N'PC')))
begin
exec @reportPackDestructorFunctionName
declare @objectsToDelete as table (Name nvarchar(2048), Type nvarchar(2048))
insert @objectsToDelete exec @reportPackDestructorFunctionName
if @Debug = 1
begin
select * from @objectsToDelete
end
declare @TablesToDelete as table(ObjectID int, Name varchar(max))
declare @FunctionsToDelete as Table(Name nvarchar(max))
declare @StoredProceduresToDelete as Table(Name nvarchar(max))
declare @AssembliesToDelete as Table(Name nvarchar(max))
declare @ViewsToDelete as Table(Name nvarchar(max))
insert into @TablesToDelete
select object_id(Name), Name
from @objectsToDelete
where Type = 'Table'
insert into @FunctionsToDelete
select Name
from @objectsToDelete
where Type = 'Function'
insert into @StoredProceduresToDelete
select Name
from @objectsToDelete
where Type = 'Procedure'
union
select @reportPackDestructorFunctionName
insert into @AssembliesToDelete
select Name
from @objectsToDelete
where Type = 'Assembly'
insert into @ViewsToDelete
select Name
from @objectsToDelete
where Type = 'View'
declare @DependencyTree as Table(ForeignKeyObjectID int, ForeignKeyObjectName nvarchar(max),
ParentTableID int, ParentTableName nvarchar(max),
ChildTableID int, ChildTableName nvarchar(max), Generation int)
declare @Generation int;
set @Generation = 0;
insert into @DependencyTree
select distinct(fk.object_id) as ForeignKeyObjectID, fk.name as ForeignKeyObjectName,
fk.referenced_object_id as ParentTableID, parent.name as ParentTableName,
fk.parent_object_id as ChildTableID, child.name as ChildTableName, @Generation
from sys.foreign_keys as fk
inner join sys.objects as parent
on fk.referenced_object_id = parent.object_id
inner join sys.objects as child
on fk.parent_object_id = child.object_id
where fk.referenced_object_id in (select ObjectID from @TablesToDelete)
while @@ROWCOUNT > 0
begin
set @Generation = @Generation + 1
insert into @DependencyTree
select fk.object_id as ForeignKeyObjectID, fk.name as ForeignKeyObjectName,
fk.referenced_object_id as ParentTableID, parent.name as ParentTableName,
fk.parent_object_id as ChildTableID, child.name as ChildTableName, @Generation
from @DependencyTree dt
inner join sys.foreign_keys as fk
on fk.referenced_object_id = dt.ChildTableID
inner join sys.objects as parent
on fk.referenced_object_id = parent.object_id
inner join sys.objects as child
on fk.parent_object_id = child.object_id
except
select ForeignKeyObjectID, ForeignKeyObjectName,
ParentTableID, ParentTableName,
ChildTableID, ChildTableName, @Generation
from @DependencyTree
end
declare @clearScript as table(ID int primary key identity (0,1), ScriptText nvarchar(max))
insert into @clearScript
select 'alter table [reporter].[' + ChildTableName +
'] drop constraint [' + ForeignKeyObjectName + ']'
from @DependencyTree
where ParentTableName in (select Name from @TablesToDelete)
insert into @clearScript
select 'drop table [reporter].[' + Name + ']' from @TablesToDelete
insert into @clearScript
select 'drop function [reporter].[' + Name + ']'
from @FunctionsToDelete
insert into @clearScript
select 'drop procedure [reporter].[' + Name + ']'
from @StoredProceduresToDelete
insert into @clearScript
select 'drop assembly [reporter].[' + Name + ']'
from @AssembliesToDelete
insert into @clearScript
select 'drop view [reporter].[' + Name + ']'
from @ViewsToDelete
if @Debug = 1
begin
select * from @clearScript
end
declare @str nvarchar(max)
declare @ID int;
set @ID = 0;
declare @MaxID int
select @MaxID = MAX(ID) from @clearScript
print ''
while @ID <= @MaxID
begin
select @str = ScriptText from @clearScript where ID = @ID
if @Emulate = 1
print(@str)
else
exec sp_executesql @statement = @str
set @ID = @ID + 1
end
end
END
Run Code Online (Sandbox Code Playgroud)
您所看到的问题是,在系统视图中的元数据的排序规则之间存在冲突-sys.foreign_keys和sys.objects-和表变量@DependencyTree。
正如@RLF 的回答中指出的那样,在将数据库更改为“包含”时,数据库元数据的整理从 DATABASE_DEFAULT(在您的情况下Latin1_General_CI_AS)更改为 CATALOG_DEFAULT(始终Latin1_General_100_CI_AS_WS_KS_SC)。这会影响name此查询中返回的字段:
SELECT fk.object_id AS [ForeignKeyObjectID], fk.name AS [ForeignKeyObjectName],
fk.referenced_object_id AS [ParentTableID], parent.name AS [ParentTableName],
fk.parent_object_id AS ChildTableID, child.name AS [ChildTableName], @Generation
FROM @DependencyTree dt
INNER JOIN sys.foreign_keys fk
ON fk.referenced_object_id = dt.ChildTableID
INNER JOIN sys.objects parent
ON fk.referenced_object_id = parent.[object_id]
INNER JOIN sys.objects child
ON fk.parent_object_id = child.[object_id]
EXCEPT
SELECT ForeignKeyObjectID, ForeignKeyObjectName,
ParentTableID, ParentTableName,
ChildTableID, ChildTableName, @Generation
FROM @DependencyTree
Run Code Online (Sandbox Code Playgroud)
的fk.name,parent.name和child.name领域都开始整理为Latin1_General_CI_AS后来改为Latin1_General_100_CI_AS_WS_KS_SC当你修改数据库,使其“载”。
抛出错误是因为两个部分中的字符串字段都EXCEPT需要匹配的排序规则。但另一部分EXCEPT是使用定义为的表变量:
DECLARE @DependencyTree as Table(ForeignKeyObjectID INT,
ForeignKeyObjectName NVARCHAR(MAX), ParentTableID INT, ParentTableName NVARCHAR(MAX),
ChildTableID INT, ChildTableName NVARCHAR(MAX), Generation INT)
Run Code Online (Sandbox Code Playgroud)
没有为NVARCHAR(MAX)字段指定排序规则(技术上应该声明为sysname——对于那个字段总是全部小写——因为这是源系统 Views of sys.objectsand的数据类型sys.foreign_keys)。虽然在包含数据库排序规则表MSDN 页面中没有提到它,但与临时表不同,表变量从数据库中获取默认排序规则,而不是从tempdb(这就是为什么您过去没有看到此错误,因为您的tempdb排序规则应该是SQL_Latin1_General_CP1_CI_AS从这就是实例整理;如果此表是临时表,您之前就会收到此错误)。因此,用于整理ForeignKeyObjectName,ParentTableName和ChildTableName领域是Latin1_General_CI_AS 并且在“包含”数据库时仍然是相同的排序规则。
将该表变量声明更改为以下内容应该可以解决此问题:
DECLARE @DependencyTree Table
(
ForeignKeyObjectID INT,
ForeignKeyObjectName sysname COLLATE CATALOG_DEFAULT,
ParentTableID INT,
ParentTableName sysname COLLATE CATALOG_DEFAULT,
ChildTableID INT,
ChildTableName sysname COLLATE CATALOG_DEFAULT,
Generation INT
);
Run Code Online (Sandbox Code Playgroud)
UsingCOLLATE CATALOG_DEFAULT将在数据库不包含时以及当它们被更改为包含时使用,因为CATALOG_DEFAULT解析为非包含数据库中的数据库默认值。说明此行为的另一种方式是,由于数据库元数据CATALOG_DEFAULT在数据库的任一状态下进行整理,因此它将在数据库的任一状态下在表变量(和临时表)中工作。
包含数据库排序规则的 MSDN 页面有一些指导,其中包括:
因此,您的问题在于目录排序规则。当您更改为包含时,它将数据库的目录排序规则更改为Latin1_General_100_CI_AS_WS_KS_SC,这是您的问题的根源。
也许关于整理的评论,特别是CATALOG_DEFAULT可以为您提供一些帮助:
包含和非包含上下文之间的交叉
此链接以结论结尾:
关于数据整理问题:
如果您也有关于决心整理问题的数据使用COLLATE DATABASE_DEFAULT。可能您的两个数据库对数据具有相同的排序规则。但如果没有,您可以使用以下技术:
select NameValue COLLATE DATABASE_DEFAULT from MyDatabase.Schema.Table
EXCEPT
select NameValue COLLATE DATABASE_DEFAULT from TheirDatabase.Schema.Table
Run Code Online (Sandbox Code Playgroud)
这种方法的价值在于您不需要指定特定的排序规则,而是COLLATE DATABASE_DEFAULT允许您使用当前数据库的排序规则。这将解决数据整理问题。