web-dev-qa-db-ja.com

照合順序の競合... dbo.sysdac_instancesを使用できませんでした

デフォルトの照合順序がLatin1_General_CI_ASであるデータベースを新しい2014サーバーに移行した後、ほとんどのデータベースの照合順序がLatin1_General_BINである場合、Excelスプレッドシートをインポートしようとすると、次のエラーがスローされます。

Collation conflict error message

私はsysdac_instancesをシステムビューであるmsdbまで追跡しましたが、直接クエリしても同じエラーが発生します。私は誰かがこの問題の簡単な解決策の方向に私を向けることができることを望んでいますか?

不思議なことに、SSMS 2008経由でインポートを実行すると機能します。

6
YaHozna

sysdac_instancesビューは次のように定義されています。

CREATE VIEW [dbo].[sysdac_instances]
AS
    SELECT
        -- this must be locked down because we use instance_id visability as a security gate
        case 
            when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.instance_id
            when sd.owner_sid = SUSER_SID() then dac_instances.instance_id
            else NULL
        end as instance_id,
        dac_instances.instance_name,
        dac_instances.type_name,
        dac_instances.type_version,
        dac_instances.description,
        case 
            when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.type_stream
            when sd.owner_sid = SUSER_SID() then dac_instances.type_stream
            else NULL
        end as type_stream,
        dac_instances.date_created,
        dac_instances.created_by,
        dac_instances.instance_name as database_name
    FROM sysdac_instances_internal dac_instances
    LEFT JOIN sys.databases sd
        ON dac_instances.instance_name = sd.name

ビューは、instance_name列に対してsys.databases.nameの結合を実行します。 sysdac_instances_internal.instance_nameの列定義では照合順序が指定されていないため、msdbデータベースの照合順序が想定されます。

おそらく、照合がLatin1_General_BINであるインスタンスからmsdbを復元したため、照合の競合が発生した可能性があります。それがである場合の場合、MSDBデータベースを再作成する必要があります。これは、その 照合順序は変更できない であるためです。

7
Max Vernon

@Maxは 正しい についてa)このエラーの根本原因(復元されたmsdbデータベースの照合は、master.sys.sysdbregnameフィールドの照合を設定するために使用されるサーバーのデフォルトの照合と一致しません- sys.databases)のnameフィールドの実際のソース、およびb)理想的にはmsdbを再構築して、サーバーのデフォルト(Latin1_General_CI_AS)に一致する照合を取得します。これを実装できるようになるまで、インポートを機能させるには2つの短期的な解決策があります理想的な解決策(そしてはい、私は両方を試しました、そしてそれらはうまくいきます:-):

  1. dbo.sysdac_instancesビューの定義を変更して、デフォルトの照合の優先順位の動作による競合を回避する照合を明示的に指定します。

    ALTER VIEW [dbo].[sysdac_instances]
    AS
        SELECT
            -- this must be locked down because we use instance_id visability as a security gate
            case 
                when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.instance_id
                when sd.owner_sid = SUSER_SID() then dac_instances.instance_id
                else NULL
            end as instance_id,
            dac_instances.instance_name,
            dac_instances.type_name,
            dac_instances.type_version,
            dac_instances.description,
            case 
                when (dbo.fn_sysdac_is_currentuser_sa() = 1) then dac_instances.type_stream
                when sd.owner_sid = SUSER_SID() then dac_instances.type_stream
                else NULL
            end as type_stream,
            dac_instances.date_created,
            dac_instances.created_by,
            dac_instances.instance_name as database_name
        FROM sysdac_instances_internal dac_instances
        LEFT JOIN sys.databases sd
            ON dac_instances.instance_name = sd.name COLLATE Latin1_General_CI_AS
    

    私はSELECT OBJECT_DEFINITION(OBJECT_ID('dbo.sysdac_instances'));を使用してその定義をDBから直接プルし、最後にCOLLATE句を追加しました。

    バイナリCollat​​ionではなくCOLLATE句でLatin1_General_CI_AS Collat​​ionを使用して追加したので、この操作(つまり、データベース名のマッチング)は、sys.databases.nameへの他の比較と同様に動作します(もちろん、COLLATEを使用してオーバーライドされませんでした)条項;-)

  2. 問題のフィールドの照合を変更します。

    USE [msdb];
    
    ALTER TABLE dbo.[sysdac_instances_internal]
          DROP CONSTRAINT [UQ_sysdac_instances_internal];
    
    ALTER TABLE dbo.[sysdac_instances_internal]
          ALTER COLUMN [instance_name] sysname COLLATE Latin1_General_CI_AS NOT NULL;
    
    ALTER TABLE dbo.[sysdac_instances_internal]
          ADD CONSTRAINT [UQ_sysdac_instances_internal]
          UNIQUE NONCLUSTERED ([instance_name] ASC);
    

2つのオプションの間で、#1(つまり、ビューの変更)は、基になるテーブルを使用してmsdbデータベース内の他の要素に悪影響を与える可能性が最も低くなります。

インスタンスとデータベースの照合を更新することを検討している場合は、次の投稿を参照してください。

インスタンス、データベース、およびすべてのユーザーデータベースのすべての列の照合順序の変更:何が問題になるのでしょうか?

その他の注意事項:

  • コードがこの特定のビューを参照していないため、SSMS 2008でインポートが機能した可能性が高いと思います。その振る舞いを説明できる他の違いは考えられません。

  • バイナリ照合順序を使用する場合は、廃止されたBIN照合順序ではなく、新しいBIN2照合順序を使用するのが最適です。

  • 可能な場合は、特定の照合の最新バージョンを使用し、_SCで終わるバリエーションがある場合はそれを選択することをお勧めします。新しいサーバーの場合は、Latin1_General_100_CI_AS_SCを選択することをお勧めします。

  • これは、DATABASE_DEFAULTと同様の特別な照合がインスタンスレベルで機能する必要がある理由のもう1つの例です。INSTANCE_DEFAULTにより、この種の問題に対する一般的な解決策が存在します。これにより、msdb.dbo.sysdac_instances_internalテーブルを次のように作成できます。

    ...
    [instance_name]   sysname COLLATE INSTANCE_DEFAULT,
    ...
    

    または、msdb.dbo.sysdac_instancesビューの最後にこれがある可能性があります。

    LEFT JOIN sys.databases sd
        ON dac_instances.instance_name = sd.name COLLATE INSTANCE_DEFAULT
    

    したがって、次の提案に投票してください。

    COLLATE DATABASE_DEFAULTのように機能するように特別な照合順序INSTANCE_DEFAULTを追加しますが、インスタンスのデフォルトの照合順序を使用します

4
Solomon Rutzky

一般に、照合は互いに一致するように説得できます。私のコメントを見てください:
含まれるDB照合エラー

おそらく、照合に関するコメント、特にCATALOG_DEFAULTは、いくつかの助けになるかもしれません。

  • データベースの照合は保持されますが、ユーザーデータのデフォルトの照合としてのみ使用されます。
  • 新しいキーワードCATALOG_DEFAULTがCOLLATE句で使用できます。これは、包含データベースと非包含データベースの両方でメタデータの現在の照合へのショートカットとして使用されます。

2つのデータベース間など、より簡単な照合問題の場合、その説明からのサンプルクエリは次のとおりです。

select NameValue COLLATE DATABASE_DEFAULT from MyDatabase.Schema.Table
EXCEPT
select NameValue COLLATE DATABASE_DEFAULT from TheirDatabase.Schema.Table

このアプローチの価値は、特定の照合を指定する必要がないことですが、COLLATE DATABASE_DEFAULTを使用すると、現在のデータベースの照合を使用できます。これにより、データ照合の問題が解決されます。

2
RLF