データベースを部分的包含に変更すると、次のエラーが発生します。
EXCEPT操作での「Latin1_General_CI_AS」と「Latin1_General_100_CI_AS_KS_WS_SC」の間の照合の競合を解決できません。
>オブジェクトのコンパイル中に、プロシージャ 'RSExecRole.DeleteExtensionModuleDDL'でエラーが発生しました。データベース 'VeeamOne'の包含オプションが変更されたか、このオブジェクトがモデルdbに存在し、ユーザーが新しい包含データベースを作成しようとしました。 ALTER DATABASEステートメントが失敗しました。 SQLモジュールの検証中にコンパイルエラーが発生したため、データベース 'VeeamOne'の包含オプションを変更できませんでした。以前のエラーを参照してください。 ALTER DATABASEステートメントが失敗しました。 (.Net SqlClientデータプロバイダー)
これが報告しているオブジェクトはSSRSからのものだと思います。ただし、照合を変更するDBは完全に別のアプリケーションです。
これを解決する方法について何か提案はありますか?
================================================== ======================= OKこれは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
表示されている問題は、システムビューのメタデータの照合-_sys.foreign_keys
_および_sys.objects
_-とテーブル変数_@DependencyTree
_の間の競合です。
@RLFの answer で指摘されているように、データベースを「」に変更すると、データベースメタデータの照合順序が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
_
_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)
_
NVARCHAR(MAX)
フィールドには照合順序が指定されていません(技術的にはsysname
として宣言する必要があります-常にすべて小文字です-これはソースシステムのデータ型であるためです。 _sys.objects
_および_sys.foreign_keys
_)。 Contained Database Collations Table 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
);
_
_COLLATE CATALOG_DEFAULT
_は非包含データベースのデフォルトに解決されるため、_CATALOG_DEFAULT
_を使用すると、データベースが含まれていない場合、およびデータベースが含まれるように変更された場合に機能します。この動作を述べるもう1つの方法は、データベースのメタデータがデータベースのどちらの状態でも_CATALOG_DEFAULT
_として照合されるため、データベースのどちらの状態でもテーブル変数(および一時テーブル)で機能するということです。
Contained Database Collations のMSDNページには、次のようなガイダンスがあります。
したがって、問題はカタログ照合にあります。包含に変更すると、データベースのカタログ照合がLatin1_General_100_CI_AS_WS_KS_SCに変更され、これが問題の原因です。
おそらく、照合に関するコメント、特にCATALOG_DEFAULTは、いくつかの支援を提供する可能性があります。
包含コンテキストと非包含コンテキストの交差
そして、このリンクは結論:で終わります
データ照合の問題について:
あなたがもする必要がある場合は、 _COLLATE DATABASE_DEFAULT
_を使用してdataの照合問題を解決します。おそらく、2つのデータベースのデータの照合順序は同じです。ただし、そうでない場合は、次の手法を使用できます。
_select NameValue COLLATE DATABASE_DEFAULT from MyDatabase.Schema.Table
EXCEPT
select NameValue COLLATE DATABASE_DEFAULT from TheirDatabase.Schema.Table
_
このアプローチの価値は、特定の照合を指定する必要がないことですが、_COLLATE DATABASE_DEFAULT
_を使用すると、現在のデータベースの照合を使用できます。これは、データ照合問題を解決します。
これは、私が実装した回避策を示すためです-両手が縛られていて、比較エラーの原因となっているソーステーブルを変更できない場合、これは機能します。 。
/* This is an interesting problem I ran across while trying to do some work in a collated database.
The SQLLogin column on the LoginsReference table is nvarchar(50) (yes, it should be sysname)
When trying to see if [name] from the sys.sysusers table existed in the LoginsReference table, I got the following error:
--Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_100_CI_AS_KS_WS_SC" in the equal to operation.
My temporary solution is to leverage implicit conversion to insert the SQLLogins FROM LoginsReference into a temp table that is properly collated, and use it for the comparison operator.
Long term solution is to properly collate things in tables. However, there is a lot of dynamic SQL involved and I'm worried there will be many more issues with other comparisons made in stored procedures elsewhere. We'll see.
*/
--this is a script to clean out users created in testing and also reset all tables involved in testing.
USE [_Contained Database]
DECLARE @UUID smallint
DECLARE @SQL nvarchar(max)
DECLARE @loginname nvarchar (20)
DECLARE @stop bit
IF OBJECT_ID('tempdb..#usernames') is NOT NULL
DROP TABLE #usernames
CREATE TABLE #usernames
([sqlLogin] nvarchar (50) COLLATE CATALOG_DEFAULT)
INSERT INTO #userNames
SELECT [sqlLogin] FROM [dbo].[LoginsReference]
WHILE EXISTS (SELECT TOP 1 [UID] FROM sys.sysusers WHERE [uid] BETWEEN 5 and 16000 and [name] in (SELECT [sqlLogin] FROM #usernames))
BEGIN
SELECT TOP 1 @loginname = [name] FROM sys.sysusers WHERE [uid] BETWEEN 5 and 16000 and [name] in (SELECT [sqlLogin] FROM #usernames)
SELECT @SQL = 'DROP USER ' + @loginname
exec sp_executesql @sql
END
TRUNCATE TABLE [dbo].[LoginRoles]
TRUNCATE TABLE [dbo].[LoginsReference]
FROM: https://github.com/scorellis/SQLTutorials/blob/master/COLLATE_Comparison_problem