Ao alterar um banco de dados para parcialmente contido, recebo o seguinte erro:
Não é possível resolver o conflito de agrupamento entre "Latin1_General_CI_AS" e "Latin1_General_100_CI_AS_KS_WS_SC" na operação EXCEPT.
Foram encontrados erros no procedimento 'RSExecRole.DeleteExtensionModuleDDL' durante a compilação do objeto >. A opção de contenção do banco de dados 'VeeamOne' foi alterada ou este objeto estava presente no modelo db e o usuário tentou criar um novo banco de dados contido. Falha na instrução ALTER DATABASE. A opção de contenção do banco de dados 'VeeamOne' não pôde ser alterada porque foram encontrados erros de compilação durante a validação dos módulos SQL. Veja os erros anteriores. Falha na instrução ALTER DATABASE. (Provedor de Dados .Net SqlClient)
Acho que o objeto que está relatando é do SSRS. No entanto, o banco de dados no qual estou alterando o agrupamento é um aplicativo completamente separado.
Alguém tem alguma sugestão de como resolver isso?
==================================================== ======================= OK, este é o código para o proc, não tenho certeza do que faz com que ele não seja capaz de ser contido
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
O problema que você está vendo é um conflito entre o agrupamento dos metadados nas exibições do sistema -
sys.foreign_keys
esys.objects
- e a variável da tabela@DependencyTree
.Conforme apontado na resposta de @RLF , o agrupamento dos metadados do banco de dados muda de DATABASE_DEFAULT (no seu caso
Latin1_General_CI_AS
) para CATALOG_DEFAULT (sempreLatin1_General_100_CI_AS_WS_KS_SC
) ao alterar o banco de dados para ser "contido". Isso afeta osname
campos que estão sendo retornados nesta consulta:Os campos
fk.name
,parent.name
echild.name
são todos agrupados inicialmente comoLatin1_General_CI_AS
, mas depois mudam paraLatin1_General_100_CI_AS_WS_KS_SC
quando você ALTER o banco de dados para torná-lo "contido".O erro está sendo lançado porque os campos de string em ambas as partes
EXCEPT
precisam ter agrupamentos correspondentes. Mas a outra parteEXCEPT
está usando a variável de tabela que é definida como:Nenhum agrupamento é especificado para os
NVARCHAR(MAX)
campos (que tecnicamente devem ser declarados comosysname
-- sempre todos em minúsculas para aquele -- já que esse é o tipo de dados das Visualizações do sistema de origem desys.objects
esys.foreign_keys
). Embora não seja mencionado na página MSDN Contained Database Collations Table , ao contrário das tabelas temporárias, as variáveis de tabela obtêm seu agrupamento padrão do banco de dados, não detempdb
(é por isso que você não viu esse erro no passado, pois seutempdb
agrupamento deve serSQL_Latin1_General_CP1_CI_AS
desde esse é o agrupamento de instâncias; você teria obtido esse erro antes se esta tabela fosse uma tabela temporária). Portanto, o agrupamento usado para os camposForeignKeyObjectName
,ParentTableName
e foiChildTableName
Latin1_General_CI_AS
e ainda será o mesmo agrupamento após o banco de dados ser "contido".Alterar essa declaração de variável de tabela para o seguinte deve resolver esse problema:
O uso
COLLATE CATALOG_DEFAULT
funcionará com bancos de dados quando eles não estiverem contidos e quando forem alterados para serem contidos, poisCATALOG_DEFAULT
resolve o padrão do banco de dados em bancos de dados não contidos. Outra maneira de declarar esse comportamento é que, como os metadados do banco de dados são agrupadosCATALOG_DEFAULT
em qualquer estado do banco de dados, eles funcionarão na variável de tabela (e nas tabelas temporárias) em qualquer estado do banco de dados.A página do MSDN em Contained Database Collations tem algumas orientações que incluem:
Portanto, seu problema é com o agrupamento de catálogos . À medida que você muda para contido, ele altera o agrupamento do catálogo do banco de dados para Latin1_General_100_CI_AS_WS_KS_SC, que é a origem do seu problema.
Talvez os comentários sobre o agrupamento, particularmente o CATALOG_DEFAULT , possam fornecer alguma ajuda:
Cruzamento entre contextos contidos e não contidos
E este link termina com a Conclusão:
Com relação aos problemas de agrupamento de dados :
Se você também tiver que resolver problemas de agrupamento nos dados usando
COLLATE DATABASE_DEFAULT
. Provavelmente seus dois bancos de dados têm o mesmo agrupamento para os dados. Mas se não, você pode usar a seguinte técnica:O valor dessa abordagem é que você não precisa especificar um agrupamento específico, mas
COLLATE DATABASE_DEFAULT
permite usar o agrupamento do banco de dados atual. Isso resolveria problemas de agrupamento de dados .Isto é para mostrar uma solução alternativa que implementei - se suas mãos estão atadas e você não pode alterar as tabelas de origem que estão causando um erro de comparação, isso funciona: Insira os valores que você precisa comparar em uma tabela temporária que tenha o atributo COLLATE CATALOG_DEFAULT conforme mencionado acima .
DE: https://github.com/scorellis/SQLTutorials/blob/master/COLLATE_Comparison_problem