web-dev-qa-db-ja.com

sys.databasesのいくつかの列の照合はどうなっていますか?

2005年から2012年までのSQL Serverのさまざまなバージョンにわたって、sys.databasesに含まれるさまざまな列でUNPIVOTを実行しようとしています。

UNPIVOTが失敗し、次のエラーメッセージが表示されます。

メッセージ8167、レベル16、状態1、行48

列「CompatibilityLevel」のタイプが、UNPIVOTリストで指定されている他の列のタイプと競合しています。

T-SQL:

DECLARE @dbname SYSNAME;
SET @dbname = DB_NAME();

SELECT [Database]            = unpvt.DatabaseName
    , [Configuration Item]   = unpvt.OptionName
    , [Configuration Value]  = unpvt.OptionValue
FROM (
    SELECT 
        DatabaseName = name 
        , RecoveryModel                 = CONVERT(VARCHAR(50), d.recovery_model_desc)
        , CompatibilityLevel            = CONVERT(VARCHAR(50), CASE d.[compatibility_level] WHEN 70 THEN 'SQL Server 7' WHEN 80 THEN 'SQL Server 2000' WHEN 90 THEN 'SQL Server 2005' WHEN 100 THEN 'SQL Server 2008' WHEN 110 THEN 'SQL Server 2012' WHEN 120 THEN 'SQL Server 2014' ELSE 'UNKNOWN' END)
        , AutoClose                     = CONVERT(VARCHAR(50), CASE d.is_auto_close_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoCreateStatistics          = CONVERT(VARCHAR(50), CASE d.is_auto_create_stats_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoShrink                    = CONVERT(VARCHAR(50), CASE d.is_auto_shrink_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoUpdateStatistics          = CONVERT(VARCHAR(50), CASE d.is_auto_update_stats_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoUpdateStatisticsAsynch    = CONVERT(VARCHAR(50), CASE d.is_auto_update_stats_async_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , CloseCursorOnCommit           = CONVERT(VARCHAR(50), CASE d.is_cursor_close_on_commit_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DefaultCursor                 = CONVERT(VARCHAR(50), CASE d.is_local_cursor_default WHEN 1 THEN 'LOCAL' ELSE 'GLOBAL' END)
        , ANSINULL_Default              = CONVERT(VARCHAR(50), CASE d.is_ansi_null_default_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSINULLS_Enabled             = CONVERT(VARCHAR(50), CASE d.is_ansi_nulls_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSIPadding_Enabled           = CONVERT(VARCHAR(50), CASE d.is_ansi_padding_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSIWarnings_Enabled          = CONVERT(VARCHAR(50), CASE d.is_ansi_warnings_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ArithmeticAbort_Enabled       = CONVERT(VARCHAR(50), CASE d.is_arithabort_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ConcatNullYieldsNull          = CONVERT(VARCHAR(50), CASE d.is_concat_null_yields_null_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , CrossDBOwnerChain             = CONVERT(VARCHAR(50), CASE d.is_db_chaining_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DateCorrelationOptimized      = CONVERT(VARCHAR(50), CASE d.is_date_correlation_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , NumericRoundAbort             = CONVERT(VARCHAR(50), CASE d.is_numeric_roundabort_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , [Parameterization]            = CONVERT(VARCHAR(50), CASE d.is_parameterization_forced WHEN 0 THEN 'SIMPLE' ELSE 'FORCED' END)
        , QuotedIdentifiers_Enabled     = CONVERT(VARCHAR(50), CASE d.is_quoted_identifier_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , RecursiveTriggers_Enabled     = CONVERT(VARCHAR(50), CASE d.is_recursive_triggers_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , [TrustWorthy]                 = CONVERT(VARCHAR(50), CASE d.is_trustworthy_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , VARDECIMAL_Storage            = CONVERT(VARCHAR(50), 'TRUE')
        , PageVerify                    = CONVERT(VARCHAR(50), page_verify_option_desc  )
        , BrokerEnabled                 = CONVERT(VARCHAR(50), CASE d.is_broker_enabled WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DatabaseReadOnly              = CONVERT(VARCHAR(50), CASE d.is_read_only WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , EncryptionEnabled             = CONVERT(VARCHAR(50), CASE d.is_encrypted WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , RestrictedAccess              = CONVERT(VARCHAR(50), user_access_desc)
        , Collation                     = CONVERT(VARCHAR(50), d.collation_name)
    FROM sys.databases d
    WHERE name = @dbname
        OR @dbname IS NULL
    ) src
UNPIVOT
(
    OptionValue FOR OptionName IN
    (
        RecoveryModel
        , CompatibilityLevel
        , AutoClose
        , AutoCreateStatistics 
        , AutoShrink 
        , AutoUpdateStatistics 
        , AutoUpdateStatisticsAsynch 
        , CloseCursorOnCommit 
        , DefaultCursor 
        , ANSINULL_Default 
        , ANSINULLS_Enabled 
        , ANSIPadding_Enabled 
        , ANSIWarnings_Enabled 
        , ArithmeticAbort_Enabled 
        , ConcatNullYieldsNull 
        , CrossDBOwnerChain 
        , DateCorrelationOptimized 
        , NumericRoundAbort 
        , [Parameterization] 
        , QuotedIdentifiers_Enabled 
        , RecursiveTriggers_Enabled 
        , [TrustWorthy] 
        , VARDECIMAL_Storage 
        , PageVerify 
        , BrokerEnabled 
        , DatabaseReadOnly 
        , EncryptionEnabled 
        , RestrictedAccess 
        , Collation
    )
) AS unpvt;

これは、次のような、指定されたデータベースのデータベースオプションのリストを適切にフォーマットするように設計されています。

+----------+----------------------------+----------------------------+
| Database | Configuration Item         | Value in Use               |
+----------+----------------------------+----------------------------+
| master   | RecoveryModel              | SIMPLE                     |
| master   | CompatibilityLevel         | SQL Server 2008            |
| master   | AutoClose                  | FALSE                      |
| master   | AutoCreateStatistics       | TRUE                       |
| master   | AutoShrink                 | FALSE                      |
| master   | AutoUpdateStatistics       | TRUE                       |
| master   | AutoUpdateStatisticsAsynch | FALSE                      |
| master   | CloseCursorOnCommit        | FALSE                      |
| master   | DefaultCursor              | GLOBAL                     |
| master   | ANSINULL_Default           | FALSE                      |
| master   | ANSINULLS_Enabled          | FALSE                      |
| master   | ANSIPadding_Enabled        | FALSE                      |
| master   | ANSIWarnings_Enabled       | FALSE                      |
| master   | ArithmeticAbort_Enabled    | FALSE                      |
| master   | ConcatNullYieldsNull       | FALSE                      |
| master   | CrossDBOwnerChain          | TRUE                       |
| master   | DateCorrelationOptimized   | FALSE                      |
| master   | NumericRoundAbort          | FALSE                      |
| master   | Parameterization           | SIMPLE                     |
| master   | QuotedIdentifiers_Enabled  | FALSE                      |
| master   | RecursiveTriggers_Enabled  | FALSE                      |
| master   | TrustWorthy                | TRUE                       |
| master   | VARDECIMAL_Storage         | TRUE                       |
| master   | PageVerify                 | CHECKSUM                   |
| master   | BrokerEnabled              | FALSE                      |
| master   | DatabaseReadOnly           | FALSE                      |
| master   | EncryptionEnabled          | FALSE                      |
| master   | RestrictedAccess           | MULTI_USER                 |
| master   | Collation                  | Latin1_General_CI_AS_KS_WS |
+----------+----------------------------+----------------------------+

Latin1_General_CI_AS_KS_WS照合を使用してサーバーでこれを実行すると、ステートメントは成功します。特定のフィールドにCOLLATE句が含まれるようにT-SQLを変更すると、他の照合順序を持つサーバーで実行されます。

Latin1_General_CI_AS_KS_WS以外の照合順序を持つサーバーで機能するコードは次のとおりです。

DECLARE @dbname SYSNAME;
SET @dbname = DB_NAME();

SELECT [Database]            = unpvt.DatabaseName
    , [Configuration Item]   = unpvt.OptionName
    , [Configuration Value]  = unpvt.OptionValue
FROM (
    SELECT 
        DatabaseName = name 
        , RecoveryModel                 = CONVERT(VARCHAR(50), d.recovery_model_desc) COLLATE SQL_Latin1_General_CP1_CI_AS
        , CompatibilityLevel            = CONVERT(VARCHAR(50), CASE d.[compatibility_level] WHEN 70 THEN 'SQL Server 7' WHEN 80 THEN 'SQL Server 2000' WHEN 90 THEN 'SQL Server 2005' WHEN 100 THEN 'SQL Server 2008' WHEN 110 THEN 'SQL Server 2012' WHEN 120 THEN 'SQL Server 2014' ELSE 'UNKNOWN' END) 
        , AutoClose                     = CONVERT(VARCHAR(50), CASE d.is_auto_close_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoCreateStatistics          = CONVERT(VARCHAR(50), CASE d.is_auto_create_stats_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoShrink                    = CONVERT(VARCHAR(50), CASE d.is_auto_shrink_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoUpdateStatistics          = CONVERT(VARCHAR(50), CASE d.is_auto_update_stats_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoUpdateStatisticsAsynch    = CONVERT(VARCHAR(50), CASE d.is_auto_update_stats_async_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , CloseCursorOnCommit           = CONVERT(VARCHAR(50), CASE d.is_cursor_close_on_commit_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DefaultCursor                 = CONVERT(VARCHAR(50), CASE d.is_local_cursor_default WHEN 1 THEN 'LOCAL' ELSE 'GLOBAL' END)
        , ANSINULL_Default              = CONVERT(VARCHAR(50), CASE d.is_ansi_null_default_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSINULLS_Enabled             = CONVERT(VARCHAR(50), CASE d.is_ansi_nulls_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSIPadding_Enabled           = CONVERT(VARCHAR(50), CASE d.is_ansi_padding_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSIWarnings_Enabled          = CONVERT(VARCHAR(50), CASE d.is_ansi_warnings_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ArithmeticAbort_Enabled       = CONVERT(VARCHAR(50), CASE d.is_arithabort_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ConcatNullYieldsNull          = CONVERT(VARCHAR(50), CASE d.is_concat_null_yields_null_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , CrossDBOwnerChain             = CONVERT(VARCHAR(50), CASE d.is_db_chaining_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DateCorrelationOptimized      = CONVERT(VARCHAR(50), CASE d.is_date_correlation_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , NumericRoundAbort             = CONVERT(VARCHAR(50), CASE d.is_numeric_roundabort_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , [Parameterization]            = CONVERT(VARCHAR(50), CASE d.is_parameterization_forced WHEN 0 THEN 'SIMPLE' ELSE 'FORCED' END)
        , QuotedIdentifiers_Enabled     = CONVERT(VARCHAR(50), CASE d.is_quoted_identifier_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , RecursiveTriggers_Enabled     = CONVERT(VARCHAR(50), CASE d.is_recursive_triggers_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , [TrustWorthy]                 = CONVERT(VARCHAR(50), CASE d.is_trustworthy_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , VARDECIMAL_Storage            = CONVERT(VARCHAR(50), 'TRUE')
        , PageVerify                    = CONVERT(VARCHAR(50), page_verify_option_desc  ) COLLATE SQL_Latin1_General_CP1_CI_AS
        , BrokerEnabled                 = CONVERT(VARCHAR(50), CASE d.is_broker_enabled WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DatabaseReadOnly              = CONVERT(VARCHAR(50), CASE d.is_read_only WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , EncryptionEnabled             = CONVERT(VARCHAR(50), CASE d.is_encrypted WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , RestrictedAccess              = CONVERT(VARCHAR(50), user_access_desc) COLLATE SQL_Latin1_General_CP1_CI_AS
        , Collation                     = CONVERT(VARCHAR(50), d.collation_name)
    FROM sys.databases d
    WHERE name = @dbname
        OR @dbname IS NULL
    ) src
UNPIVOT
(
    OptionValue FOR OptionName IN
    (
        RecoveryModel
        , CompatibilityLevel
        , AutoClose
        , AutoCreateStatistics 
        , AutoShrink 
        , AutoUpdateStatistics 
        , AutoUpdateStatisticsAsynch 
        , CloseCursorOnCommit 
        , DefaultCursor 
        , ANSINULL_Default 
        , ANSINULLS_Enabled 
        , ANSIPadding_Enabled 
        , ANSIWarnings_Enabled 
        , ArithmeticAbort_Enabled 
        , ConcatNullYieldsNull 
        , CrossDBOwnerChain 
        , DateCorrelationOptimized 
        , NumericRoundAbort 
        , [Parameterization] 
        , QuotedIdentifiers_Enabled 
        , RecursiveTriggers_Enabled 
        , [TrustWorthy] 
        , VARDECIMAL_Storage 
        , PageVerify 
        , BrokerEnabled 
        , DatabaseReadOnly 
        , EncryptionEnabled 
        , RestrictedAccess 
        , Collation
    )
) AS unpvt;

観察された動作は、以下のフィールドはサーバーの照合もデータベースの照合も観察しないことです。それらはalwaysLatin1_General_CI_AS_KS_WS照合で提示されます。

SQL Server 2012では、sys.sp_describe_first_result_setを使用して、特定のクエリから返された列に関するメタデータを簡単に取得できます。以下を使用して、照合の不一致を判別しました。

DECLARE @cmd NVARCHAR(MAX);

SET @cmd = '
SELECT 
    DatabaseName                    = CONVERT(VARCHAR(50), d.name)
    , RecoveryModel                 = CONVERT(VARCHAR(50), d.recovery_model_desc) 
    , Collation                     = CONVERT(VARCHAR(50), d.collation_name)
FROM sys.databases d
WHERE name = DB_NAME();
';

EXEC sp_describe_first_result_set @command = @cmd;

結果:

enter image description here

これらの列の照合が静的に設定されるのはなぜですか?

21
Max Vernon

マイクロソフトからの公式の言葉:

事前定義された文字列(タイプ、システムの説明、定数など)を含む一部の列は、常に特定の照合順序Latin1_General_CI_AS_KS_WSに固定されています。これは、インスタンス/データベースの照合とは無関係です。その理由は、これはシステムメタデータ(ユーザーメタデータではない)であり、基本的にこれらの文字列は大文字と小文字を区別せずに処理されるためです(キーワードのように常にラテン語です)。

オブジェクト名、列名、インデックス名、ログイン名などのユーザーメタデータを含むシステムテーブルの他の列は、インスタンスまたはデータベースの照合順序をとります。インスタンス照合の場合はSQL Serverのインストール時、およびデータベース照合の場合はデータベースの作成時に、列は適切な照合に照合されます。

あなたは尋ねました(私の強調):

なぜこれらの列の照合は静的に設定されていますか?

一部の列が静的に設定される理由は、クエリがサーバーまたはデータベースの照合(さらに重要なこと:CaSe SenSiTIviTy)が正しく機能することを心配する必要がないようにするためです。このクエリは、照合に関係なく常に機能します。

SELECT * FROM sys.databases WHERE state_desc = N'ONLine';

一方、サーバーの照合で大文字と小文字が区別される場合、上記のクエリは次のように0行を返します。

  SELECT * FROM sys.databases 
  WHERE state_desc COLLATE Albanian_BIN = N'ONLine';

たとえば、SQL_Estonian_CP1257_CS_AS照合を使用してSQL Serverのインスタンスをインストールする場合は、次のコマンドを実行します。

SELECT name, collation_name 
FROM master.sys.all_columns
WHERE collation_name IS NOT NULL
AND [object_id] = OBJECT_ID(N'sys.databases');

次の結果が表示されます(SQL Serverのバージョンによっては、同様の結果になります)。

name                            SQL_Estonian_CP1257_CS_AS
collation_name                  SQL_Estonian_CP1257_CS_AS
user_access_desc                Latin1_General_CI_AS_KS_WS
state_desc                      Latin1_General_CI_AS_KS_WS
snapshot_isolation_state_desc   Latin1_General_CI_AS_KS_WS
recovery_model_desc             Latin1_General_CI_AS_KS_WS
page_verify_option_desc         Latin1_General_CI_AS_KS_WS
log_reuse_wait_desc             Latin1_General_CI_AS_KS_WS
default_language_name           SQL_Estonian_CP1257_CS_AS
default_fulltext_language_name  SQL_Estonian_CP1257_CS_AS
containment_desc                Latin1_General_CI_AS_KS_WS
delayed_durability_desc         SQL_Estonian_CP1257_CS_AS

次に、masterデータベースからサーバーの照合順序を継承するのではなく、データベースの照合順序を継承するメタデータビューを示します。

CREATE DATABASE server_collation;
GO
CREATE DATABASE albanian COLLATE Albanian_BIN;
GO
CREATE DATABASE hungarian COLLATE Hungarian_Technical_100_CS_AI;
GO

SELECT name, collation_name 
  FROM server_collation.sys.all_columns 
  WHERE collation_name IS NOT NULL 
  AND object_id = -391; -- sys.columns

SELECT name, collation_name 
  FROM albanian.sys.all_columns 
  WHERE collation_name IS NOT NULL 
  AND object_id = -391; -- sys.columns

SELECT name, collation_name 
  FROM hungarian.sys.all_columns 
  WHERE collation_name IS NOT NULL 
  AND object_id = -391; -- sys.columns

結果:

server_collation
----------------
name                                 SQL_Estonian_CP1257_CS_AS
collation_name                       SQL_Estonian_CP1257_CS_AS
generated_always_type_desc           Latin1_General_CI_AS_KS_WS
encryption_type_desc                 Latin1_General_CI_AS_KS_WS
encryption_algorithm_name            Latin1_General_CI_AS_KS_WS
column_encryption_key_database_name  SQL_Estonian_CP1257_CS_AS


albanian
----------------
name                                 Albanian_BIN
collation_name                       Albanian_BIN
generated_always_type_desc           Latin1_General_CI_AS_KS_WS
encryption_type_desc                 Latin1_General_CI_AS_KS_WS
encryption_algorithm_name            Latin1_General_CI_AS_KS_WS
column_encryption_key_database_name  Albanian_BIN


hungarian
----------------
name                                 Hungarian_Technical_100_CS_AI
collation_name                       Hungarian_Technical_100_CS_AI
generated_always_type_desc           Latin1_General_CI_AS_KS_WS
encryption_type_desc                 Latin1_General_CI_AS_KS_WS
encryption_algorithm_name            Latin1_General_CI_AS_KS_WS
column_encryption_key_database_name  Hungarian_Technical_100_CS_AI

したがって、この場合、いくつかの列はデータベース照合を継承し、他の列はこの「汎用」Latin1照合に固定されていることがわかります。つまり、特定の名前とプロパティを上記の大文字と小文字の区別の問題から隔離するために使用されます。

たとえば、UNIONを実行しようとすると、次のようになります。

SELECT name FROM albanian.sys.columns
UNION ALL
SELECT name FROM server_collation.sys.columns;

あなたはこのエラーを受け取ります:

メッセージ451、レベル16、状態1
SELECTステートメントの列1で発生するUNION ALL演算子の「Albanian_BIN」と「SQL_Estonian_CP1257_CS_AS」の間の照合の競合を解決できません.

同様に、PIVOTまたはUNPIVOTを実行しようとすると、ルールはさらに厳しくなります(出力タイプはすべて一致する必要があります正確に単に互換性があるのではなく)、しかしエラーメッセージはあまり役に立たず、誤解を招くほどです:

メッセージ8167、レベル16、状態1
列「列名」のタイプが、UNPIVOTリストで指定されている他の列のタイプと競合しています。

クエリで明示的なCOLLATE句を使用して、これらのエラーを回避する必要があります。たとえば、上記の共用体は次のようになります。

SELECT name COLLATE Latin1_General_CI_AS_KS_WS
  FROM albanian.sys.columns
UNION ALL
SELECT name COLLATE Latin1_General_CI_AS_KS_WS
  FROM server_collation.sys.columns;

これが問題を引き起こす可能性があるのは、照合が強制されているが同じ文字表現が含まれていない場合、またはソートが使用され、強制された照合でソースとは異なるソート順が使用されている場合に、出力が混乱する場合のみです。

17
Aaron Bertrand

照合順序の優先順位の背景

システムカタログビューのさまざまなフィールドの照合順序に関して表示される動作は、各フィールドの定義方法と照合順序の結果です。

_sys.databases_を見るとき、それがテーブルではないことを覚えておくことが重要です。以前は(SQL Server 2000で終わると思います)これらはシステムカタログtablesでしたが、現在はシステムカタログviewsになっています。したがって、それらの情報のソースは、必ずしも現在のデータベースコンテキスト(または_master.sys.databases_などの完全修飾オブジェクトを処理するときの指定されたデータベースのコンテキスト)からのものであるとは限りません。

特に_sys.databases_を扱うと、一部のフィールドは_[master]_データベース(インスタンスのデフォルトの照合に基づく照合で作成されたもの-サーバーレベルの照合)から取得され、一部のフィールドは式(つまりCASEステートメント)、および一部は「非表示」ソース、つまり_[mssqlsystemresource]_データベースからのものです。また、_[mssqlsystemresource]_データベースには、_Latin1_General_CI_AS_KS_WS_という照合順序があります。

nameフィールドは、_master.sys.sysdbreg_のnameフィールドから供給されます。したがって、このフィールドは常に_[master]_データベースの照合にある必要があり、これもサーバーの照合に一致します。

ただし、_sys.databases_の以下のフィールドは、_[name]_の_[mssqlsystemresource].[sys].[syspalvalues]_フィールドから取得されます。

  • user_access_desc
  • snapshot_isolation_state_desc
  • recovery_model_desc
  • page_verify_option_desc
  • log_reuse_wait_desc
  • containsment_desc

これらのフィールドには常に_Latin1_General_CI_AS_KS_WS_の照合順序が必要です。

ただし、_collation_name_フィールドは次の式から取得されます。

_CONVERT(nvarchar(128),
        CASE
            WHEN serverproperty('EngineEdition')=5
                   AND [master].[sys].[sysdbreg].[id] as [d].[id]=(1)
              THEN serverproperty('collation')
            ELSE collationpropertyfromid(
                           CONVERT(int,
                            isnull([master].[sys].[sysobjvalues].[value] as [coll].[value],
                                   CONVERT_IMPLICIT(sql_variant,DBPROP.[cid],0)
                                ),
                         0),'name')
         END,
        0)
_

これが Collat​​ion Precedence の登場です。ここでの出力の両方のオプションは、システム関数です:serverproperty()およびcollationpropertyfromid()この式の照合は、「強制可能なデフォルト」と見なされます。

Transact-SQL文字列変数、パラメーター、リテラル、またはカタログ組み込み関数の出力、または文字列入力をとらずに文字列出力を生成する組み込み関数。

オブジェクトがユーザー定義関数、ストアドプロシージャ、またはトリガーで宣言されている場合、オブジェクトには、関数、ストアドプロシージャ、またはトリガーが作成されたデータベースの既定の照合順序が割り当てられます。オブジェクトがバッチで宣言されている場合、オブジェクトには、接続用の現在のデータベースのデフォルトの照合が割り当てられます。

その2番目の段落に照らして、_sys.databases_はmasterデータベースに存在するビューであるため、masterデータベース(現在のデータベースではない)の照合順序になります。

_state_desc_フィールドも式です。

_CASE
   WHEN serverproperty('EngineEdition')=5
       AND [Expr1081]=(1)
       THEN N'RESTORING'
   ELSE
      CASE
         WHEN serverproperty('EngineEdition')=5
            AND CONVERT(bit,
                        [master].[sys].[sysdbreg].[status] as [d].[status]&(128),
                        0)=(1)
          THEN N'COPYING'
         ELSE
            CASE
               WHEN serverproperty('EngineEdition')=5
                  AND CONVERT(bit,
                              [master].[sys].[sysdbreg].[status] as [d].[status]&(256),
                              0)=(1)
                 THEN N'SUSPECT'
            ELSE [mssqlsystemresource].[sys].[syspalvalues].[name] as [st].[name]
            END
         END
       END
_

ただし、この式の照合は_Latin1_General_CI_AS_KS_WS_です。どうして?さて、この式には新しいものが導入されています。実際のフィールドへの参照:最後のELSE句の_[mssqlsystemresource].[sys].[syspalvalues].[name]_列参照は「暗黙的」と見なされます。

列参照。式の照合は、テーブルまたはビューの列に定義されている照合から取得されます。

もちろん、これは興味深い質問を開きます。この式は、CASEの評価方法に応じて異なる照合を返すことができますか?リテラルは、このオブジェクトが定義されているデータベースの照合にありますが、ELSE条件は、元の照合を保持する必要があるフィールド値を返します。さいわい、 sys.dm_exec_describe_first_result_set 動的管理関数を使用してテストをシミュレートできます。

_-- Force ELSE condition
SELECT system_type_name, max_length, collation_name
FROM sys.dm_exec_describe_first_result_set(N'
DECLARE @A INT;
SET @A = -1;
SELECT CASE WHEN @A = 100 THEN N''All About the Benjamins''
            ELSE [name]
       END AS [Stuff]
FROM msdb.dbo.sysjobs
', NULL, NULL) rs

-- Force WHEN condition
SELECT system_type_name, max_length, collation_name
FROM sys.dm_exec_describe_first_result_set(N'
DECLARE @A INT;
SET @A = 100;
SELECT CASE WHEN @A = 100 THEN N''All About the Benjamins''
            ELSE [name]
       END AS [Stuff]
FROM msdb.dbo.sysjobs
', NULL, NULL) rs

-- Control test
SELECT system_type_name, max_length, collation_name
FROM sys.dm_exec_describe_first_result_set(N'
DECLARE @A INT;
SET @A = 100;
SELECT CASE WHEN @A = 100 THEN N''All About the Benjamins''
            ELSE N''Whazzup, yo?!?!?''
       END AS [Stuff]
', NULL, NULL) rs
_

戻り値(照合順序が_SQL_Latin1_General_CP1_CI_AS_で設定されているが、照合順序が_Japanese_Unicode_CI_AS_のデータベースで実行されているインスタンス):

_system_type_name    max_length    collation_name
----------------    ----------    --------------
nvarchar(128)       256           SQL_Latin1_General_CP1_CI_AS
nvarchar(128)       256           SQL_Latin1_General_CP1_CI_AS
nvarchar(23)         46           Japanese_Unicode_CI_AS
_

ここでは、_[msdb]_のフィールドを参照する2つのクエリが_[msdb]_データベース(システムDBであり、サーバーの照合順序によって決定された)の照合順序を取得していることがわかります。

元の質問に戻る

観察された動作は、以下のフィールドはサーバーの照合もデータベースの照合も観察しないことです。それらはalways _Latin1_General_CI_AS_KS_WS_照合で提示されます。

サーバーの照合またはデータベースの照合に関係なく、これらのフィールドの照合は常に_Latin1_General_CI_AS_KS_WS_の照合になります。そしてその理由は、照合の優先順位です。これらのフィールドは_[mssqlsystemresource]_データベースのテーブルから取得され、優先度が最も高いため、明示的なCOLLATE句でオーバーライドされない限り、最初の照合を保持します。

Explicit =式でCOLLATE句を使用して特定の照合に明示的にキャストされる式。

明示は暗黙よりも優先されます。暗黙はCoercible-defaultに優先します。
明示的>暗黙的>強制デフォルト

そして関連する質問:

これらの列の照合が静的に設定されるのはなぜですか?

それらが静的に設定されているということでも、他のフィールドが何らかの形で動的であるということでもありません。これらのすべてのシステムカタログビューのすべてのフィールドは、照合順序の同じルールで動作します。それらが他のフィールドよりも「静的」であるように見える理由(つまり、SQL Serverを別のデフォルト照合でインストールしても変更されないため、デフォルト照合でシステムデータベースが作成される)は、_[mssqlsystemresource]_データベースは、SQL Serverのすべてのインストールで一貫して_Latin1_General_CI_AS_KS_WS_の照合順序を持っています(または確実に表示されます)。 SQL Server自体を内部で管理するのが難しいため(つまり、内部ロジックに使用される並べ替えおよび比較ルールがインストールに基づいて変更された場合)、これは理にかなっています。

これらの詳細を自分で確認する方法

これらのシステムカタログビューのいずれかでフィールドのソースを表示する場合は、次の操作を行います。

  1. SSMSのクエリタブで、[実際の実行プランを含める]のクエリオプションを有効にします(CTRL-M
  2. システムカタログビューの1つから1つのフィールドを選択してクエリを実行します(実行プランは1つのフィールドだけでも途方もなく大きく/複雑であり、多くのフィールドへの参照が含まれるため、一度に1つのフィールドのみを選択することをお勧めします。 t選択):

    _SELECT recovery_model_desc FROM sys.databases;
    _
  3. 「実行計画」タブに移動します
  4. グラフィカルな実行計画領域を右クリックし、[実行計画XMLを表示...]を選択します。
  5. SSMSの新しいタブが開き、次のようなタイトルが表示されます:_Execution plan.xml_
  6. _Execution plan.xml_タブに移動します
  7. _<OutputList>_タグの最初の出現を探します(通常は10行目と20行目の間にある必要があります)
  8. _<ColumnReference>_タグが必要です。そのタグの属性は、テーブルの特定のフィールドを指すか、計画の後半で定義された式を指す必要があります。
  9. 属性が実際のフィールドを指している場合、それはすべての情報を持っているので完了です。以下は、_recovery_model_desc_フィールドの表示です。

    _<ColumnReference Database="[mssqlsystemresource]" Schema="[sys]"
                     Table="[syspalvalues]" Alias="[ro]" Column="name" />
    _
  10. 代わりに_state_desc_フィールドを選択した場合など、属性が式を指す場合、最初に次のことがわかります。

    _<ColumnReference Column="Expr1024" />
    _
  11. この場合、_Expr1024_の定義やそれが思いつく#ものについて、残りの計画を調べる必要があります。これらの参照がいくつか存在する可能性があることに注意してください。ただし、定義は_<OutputList>_ブロックには含まれません。ただし、その定義を含む_<ScalarOperator>_兄弟要素があります。以下は、_state_desc_フィールドの表示です。

    _<ScalarOperator ScalarString="CASE WHEN serverproperty('EngineEdition')=5 AND [Expr1081]=(1) THEN N'RESTORING' ELSE CASE WHEN serverproperty('EngineEdition')=5 AND CONVERT(bit,[master].[sys].[sysdbreg].[status] as [d].[status]&amp;(128),0)=(1) THEN N'COPYING' ELSE CASE WHEN serverproperty('EngineEdition')=5 AND CONVERT(bit,[master].[sys].[sysdbreg].[status] as [d].[status]&amp;(256),0)=(1) THEN N'SUSPECT' ELSE [mssqlsystemresource].[sys].[syspalvalues].[name] as [st].[name] END END END">
    _

データベースレベルのカタログビューのソースを確認する場合も同様です。 _sys.tables_のようなオブジェクトに対してこれを行うと、nameフィールドが_[current_db].[sys].[sysschobjs]_(データベースの照合と照合が一致する理由)から取得されることが示されますが、_lock_escalation_desc_フィールドは_[mssqlsystemresource].[sys].[syspalvalues]_から取得されます(これが_Latin1_General_CI_AS_KS_WS_の照合順序を持つ理由です)。

Clippyは、「UNPIVOTクエリを実行したいようです」と述べています。

照合の優先順位とは何か、どのように機能するかがわかったところで、その知識をUNPIVOTクエリに適用してみましょう。

UNPIVOT操作の場合、SQL Serverは各ソースフィールドが完全に同じ型であることを本当に好むようです(つまり、必要です)。通常、「タイプ」は基本タイプ(つまりVARCHAR/NVARCHAR/INT /など)を指しますが、ここではSQL ServerにもCOLLATIONが含まれています。これは、照合が制御するもの、VARCHARの文字セット(つまり、コードページ)、および文字の等価性と文字の組み合わせ(つまり、正規化)を決定する言語規則を考えると、不当なものと見なされるべきではありません。以下は、Unicodeの「正規化」とは何かに関するmimi-primerです。

_PRINT '---';
IF (N'aa' COLLATE Danish_Greenlandic_100_CI_AI = N'å' COLLATE Danish_Greenlandic_100_CI_AI)
     PRINT 'Danish_Greenlandic_100_CI_AI';
IF (N'aa' COLLATE SQL_Latin1_General_CP1_CI_AI = N'å' COLLATE SQL_Latin1_General_CP1_CI_AI)
     PRINT 'SQL_Latin1_General_CP1_CI_AI';
PRINT '---';
IF (N'of' COLLATE Upper_Sorbian_100_CI_AI =  N'öf' COLLATE Upper_Sorbian_100_CI_AI)
     PRINT 'Upper_Sorbian_100_CI_AI';
IF (N'of' COLLATE German_PhoneBook_CI_AI =  N'öf' COLLATE German_PhoneBook_CI_AI)
     PRINT 'German_PhoneBook_CI_AI';
PRINT '---';
_

戻り値:

_---
Danish_Greenlandic_100_CI_AI
---
Upper_Sorbian_100_CI_AI
---
_

それでは、元のクエリを開始しましょう。さまざまな変更が結果をどのように変更するかを確認するためにいくつかのテストを行い、次にいくつかの変更だけでそれを修正できることを確認します。

  1. 最初のエラーは、ピボット解除される2番目のフィールドであるCompatibilityLevelフィールドに関するもので、たまたますべての文字列リテラルを含む式です。フィールド参照がない場合、結果の照合は「強制可能なデフォルト」と見なされます)。強制可能なデフォルトは、現在のデータベースの照合を引き受けます。たとえば、_SQL_Latin1_General_CP1_CI_AS_とします。次の20ほどのフィールドも文字列リテラルのみであるため、強制可能なデフォルトであるため、競合しないようにする必要があります。しかし、最初のフィールド_recovery_model_desc_を振り返ると、これは_sys.databases_のフィールドから直接取得されているため、「暗黙的な」照合になり、notになります。ローカルDBの照合順序を使用しますが、代わりに元の照合順序、つまり_Latin1_General_CI_AS_KS_WS_を保持します(実際には_[mssqlsystemresource]_ DBからのものであるため)。

    したがって、フィールド1(RecoveryModel)が_Latin1_General_CI_AS_KS_WS_であり、フィールド2(CompatibilityLevel)が_SQL_Latin1_General_CP1_CI_AS_である場合、フィールド2を_Latin1_General_CI_AS_KS_WS_にして、フィールド1と一致させることができます。次に、フィールド3(AutoClose)のエラーが表示されます。

    以下をCompatibilityLevel行の最後に追加します。
    _COLLATE Latin1_General_CI_AS_KS_WS_

    次にクエリを実行します。案の定、エラーは、競合しているのはAutoCloseフィールドであることを示しています。

  2. 2番目のテストでは、今行った変更を元に戻す必要があります(つまり、COLLATE行の末尾からCompatibilityLevel句を削除します。

    これで、SQL Serverがフィールドが指定された順序で真に評価している場合、フィールド1(RecoveryModel)を削除できるはずです。これにより、現在のフィールド2(CompatibilityLevel)がマスター照合を設定するフィールドになります。結果のUNPIVOT。また、CompatibilityLevelフィールドはデータベースの照合順序をとる強制可能なデフォルトであるため、最初のエラーは、フィールド参照であるPageVerifyフィールドである必要があります。これは、オリジナルを保持する暗黙的な照合順序です。照合。この場合は_Latin1_General_CI_AS_KS_WS_であり、現在のDBの照合ではありません。

    したがって、SELECTの_, RecoveryModel_で始まる行を(先頭に向かって)コメントアウトしてから、下のRecoveryModel句のUNPIVOT行をコメントアウトします。 CompatibilityLevelの次の行から先頭のコンマを削除して、構文エラーが発生しないようにします。

    そのクエリを実行します。案の定、エラーは、競合しているのはPageVerifyフィールドであることを示しています。

  3. 3番目のテストでは、RecoveryModelフィールドを削除するために行った変更を元に戻す必要があります。したがって、先に進んでコンマを元に戻し、他の2つの行のコメントを外してください。

    これで、照合を強制して別の方向に進むことができます。強制デフォルトの照合フィールド(ほとんどのフィールド)の照合を変更するのではなく、暗黙的な照合フィールドを現在のDBの照合に変更できますか?

    したがって、最初のテストと同様に、明示的なCOLLATE句を使用して、フィールド1(RecoveryModel)の照合を強制できます。ただし、特定の照合を指定してから、別の照合を使用してデータベースでクエリを実行すると、強制デフォルトの照合フィールドは新しい照合を取得し、この最初のフィールドの設定と競合します。それは苦痛のようです。幸いなことに、これに対処する動的な方法があります。現在のデータベースの照合を取得する_DATABASE_DEFAULT_という疑似照合があります(coercible-defaultフィールドのように)。

    先に進み、_, RecoveryModel_で始まる行の最後の上部に、以下を追加します:_COLLATE DATABASE_DEFAULT_

    そのクエリを実行します。案の定、エラーは再び、競合があるのはPageVerifyフィールドであることを示しています。

  4. 最終テストでは、以前の変更を元に戻す必要はありません。

    このUNPIVOTクエリを修正するために必要なのは、_COLLATE DATABASE_DEFAULT_を残りの暗黙的な照合フィールドの最後に追加することだけです:PageVerifyおよびRestrictedAccessCollationフィールドも暗黙的な照合ですが、そのフィールドはmasterデータベースから取得されます。これは通常、「現在の」データベースと一致しています。ただし、これが常に機能するように安全にしたい場合は、そのフィールドの最後にも_COLLATE DATABASE_DEFAULT_を追加してください。

    そのクエリを実行します。案の定、エラーはありません。このクエリを修正するために必要なのは、_COLLATE DATABASE_DEFAULT_を3つのフィールドの最後(必須)と、おそらく1つ(オプション)に追加することだけでした。

  5. オプションのテスト:UNPIVOTクエリが正しく機能するようになったので、次のように、CONVERT(VARCHAR(50),で始まるフィールド定義の1つだけを_51_に変更します。CONVERT(VARCHAR(51),

    クエリを実行します。一致しないのは照合順序のみの場合と同じ_The type of column "X" conflicts with the type of other columns specified in the UNPIVOT list._エラーが表示されます。

    データ型と照合の不一致の両方で同じエラーを取得することは、本当に役立つほど具体的ではありません。ですから、改善の余地は確かにあります:)。


照合に関する特定の質問よりもクエリに関連する注意:

すべてのソースフィールドはデータ型NVARCHARであるため、CONVERTではなくNVARCHARにすべての出力フィールドをVARCHARするほうが安全です。現在、非標準のASCII文字が含まれているデータを処理していない可能性がありますが、システムメタデータはそれらを許可しているため、NVARCHAR(128)に変換します-これは、任意の文字列の最大長ですこれらのフィールドのうち、少なくとも将来的に問題が発生しないこと、またはこのコードをコピーする他の誰かがシステムにこれらの文字をすでに持っている可能性があることを保証します。

7
Solomon Rutzky

これは、質問に対する完全な回答ではなく、特定の問題の回避策です。エラーを回避するには、varchar(50)ではなく_sql_variant_に変換します。

_DECLARE @dbname SYSNAME;
SET @dbname = DB_NAME();

SELECT [Database]            = unpvt.DatabaseName
    , [Configuration Item]   = unpvt.OptionName
    , [Configuration Value]  = unpvt.OptionValue
    , [BaseType] = SQL_VARIANT_PROPERTY(unpvt.OptionValue, 'BaseType')
    , [MaxLength] = SQL_VARIANT_PROPERTY(unpvt.OptionValue, 'MaxLength')
    , [Collation] = SQL_VARIANT_PROPERTY(unpvt.OptionValue, 'Collation')
FROM (
    SELECT 
        DatabaseName = name 
        , RecoveryModel                 = CONVERT(sql_variant, d.recovery_model_desc)
        , CompatibilityLevel            = CONVERT(sql_variant, CASE d.[compatibility_level] WHEN 70 THEN 'SQL Server 7' WHEN 80 THEN 'SQL Server 2000' WHEN 90 THEN 'SQL Server 2005' WHEN 100 THEN 'SQL Server 2008' WHEN 110 THEN 'SQL Server 2012' WHEN 120 THEN 'SQL Server 2014' ELSE 'UNKNOWN' END)
        , AutoClose                     = CONVERT(sql_variant, CASE d.is_auto_close_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoCreateStatistics          = CONVERT(sql_variant, CASE d.is_auto_create_stats_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoShrink                    = CONVERT(sql_variant, CASE d.is_auto_shrink_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoUpdateStatistics          = CONVERT(sql_variant, CASE d.is_auto_update_stats_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , AutoUpdateStatisticsAsynch    = CONVERT(sql_variant, CASE d.is_auto_update_stats_async_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , CloseCursorOnCommit           = CONVERT(sql_variant, CASE d.is_cursor_close_on_commit_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DefaultCursor                 = CONVERT(sql_variant, CASE d.is_local_cursor_default WHEN 1 THEN 'LOCAL' ELSE 'GLOBAL' END)
        , ANSINULL_Default              = CONVERT(sql_variant, CASE d.is_ansi_null_default_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSINULLS_Enabled             = CONVERT(sql_variant, CASE d.is_ansi_nulls_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSIPadding_Enabled           = CONVERT(sql_variant, CASE d.is_ansi_padding_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ANSIWarnings_Enabled          = CONVERT(sql_variant, CASE d.is_ansi_warnings_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ArithmeticAbort_Enabled       = CONVERT(sql_variant, CASE d.is_arithabort_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , ConcatNullYieldsNull          = CONVERT(sql_variant, CASE d.is_concat_null_yields_null_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , CrossDBOwnerChain             = CONVERT(sql_variant, CASE d.is_db_chaining_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DateCorrelationOptimized      = CONVERT(sql_variant, CASE d.is_date_correlation_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , NumericRoundAbort             = CONVERT(sql_variant, CASE d.is_numeric_roundabort_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , [Parameterization]            = CONVERT(sql_variant, CASE d.is_parameterization_forced WHEN 0 THEN 'SIMPLE' ELSE 'FORCED' END)
        , QuotedIdentifiers_Enabled     = CONVERT(sql_variant, CASE d.is_quoted_identifier_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , RecursiveTriggers_Enabled     = CONVERT(sql_variant, CASE d.is_recursive_triggers_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , [TrustWorthy]                 = CONVERT(sql_variant, CASE d.is_trustworthy_on WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , VARDECIMAL_Storage            = CONVERT(sql_variant, 'TRUE')
        , PageVerify                    = CONVERT(sql_variant, page_verify_option_desc  )
        , BrokerEnabled                 = CONVERT(sql_variant, CASE d.is_broker_enabled WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , DatabaseReadOnly              = CONVERT(sql_variant, CASE d.is_read_only WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , EncryptionEnabled             = CONVERT(sql_variant, CASE d.is_encrypted WHEN 0 THEN 'FALSE' ELSE 'TRUE' END)
        , RestrictedAccess              = CONVERT(sql_variant, user_access_desc)
        , Collation                     = CONVERT(sql_variant, d.collation_name)
    FROM sys.databases d
    WHERE name = @dbname
        OR @dbname IS NULL
    ) src
UNPIVOT
(
    OptionValue FOR OptionName IN
    (
        RecoveryModel
        , CompatibilityLevel
        , AutoClose
        , AutoCreateStatistics 
        , AutoShrink 
        , AutoUpdateStatistics 
        , AutoUpdateStatisticsAsynch 
        , CloseCursorOnCommit 
        , DefaultCursor 
        , ANSINULL_Default 
        , ANSINULLS_Enabled 
        , ANSIPadding_Enabled 
        , ANSIWarnings_Enabled 
        , ArithmeticAbort_Enabled 
        , ConcatNullYieldsNull 
        , CrossDBOwnerChain 
        , DateCorrelationOptimized 
        , NumericRoundAbort 
        , [Parameterization] 
        , QuotedIdentifiers_Enabled 
        , RecursiveTriggers_Enabled 
        , [TrustWorthy] 
        , VARDECIMAL_Storage 
        , PageVerify 
        , BrokerEnabled 
        , DatabaseReadOnly 
        , EncryptionEnabled 
        , RestrictedAccess 
        , Collation
    )
) AS unpvt;
_

OptionValue列の基礎となるタイプに関する情報のために3つの列を追加しました。

Sample output

クライアントが_sql_variant_データを処理できない場合は、_unpvt.OptionValue_列で最終(トップレベル)変換を実行して、たとえばnvarchar(256)

5
Paul White 9

わかりましたので、私は見てみました

sp_helptext [sys.databases]

それから、柱がどこから来ているのかを壊しました。 Latin1_General_CI_AS_KS_WS照合順序を持つものはすべて、汎用ルックアップテーブルのように見えるシステムテーブルsys.syspalvaluesから取得されます(これはシステムテーブルであるため、DACを介して接続する必要があります。 。)。

私の推測では、可能なルックアップ値を処理するためにLatin1_General_CI_AS_KS_WSに設定されています。しかし、それがいかに煩わしいかはわかります。

定義を確認する別の方法(元はコメントで Max によって提供されていました)は次のとおりです。

SELECT ObjectSchema = s.name
    , ObjectName = o.name
    , ObjectDefinition = sm.definition
FROM master.sys.all_sql_modules sm
    INNER JOIN master.sys.system_objects o ON sm.object_id = o.object_id
    INNER JOIN master.sys.schemas s ON o.schema_id = s.schema_id
WHERE s.name = 'sys' 
    AND o.name = 'databases';`
4
Kenneth Fisher