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


21

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

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;

観察された動作では、次のフィールドはサーバーの照合もデータベースの照合も観察しません。それらは常にLatin1_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;

結果:

ここに画像の説明を入力してください

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

回答:


17

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

定義済みの文字列(型、システムの説明、定数など)を含む列の一部は、常に特定の照合順序に固定されます– 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

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

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;

これが問題を引き起こす可能性があるのは、照合が強制されているが同じ文字表現が含まれていない場合、または並べ替えが使用され、強制照合がソースとは異なる並べ替え順序を使用している場合、混乱する出力が得られることだけです。


7

照合順序の背景

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

を見るときsys.databases、テーブルではないことに注意することが重要です。過去(SQL Server 2000で終わると思います)は、システムカタログテーブルでしたが、現在はシステムカタログビューです。したがって、それらの情報のソースは、必ずしも現在のデータベースコンテキスト(またはなどの完全修飾オブジェクトを処理する場合は指定されたデータベースのコンテキスト)から来るわけではありませんmaster.sys.databases

具体的にはsys.databases[master]データベースの一部のフィールド(インスタンスのデフォルトの照合に基づく照合で作成された-サーバーレベルの照合)、フィールドの一部は式(つまりCASEステートメント)であり、一部はデータベースから取得されます「隠された」ソースから:[mssqlsystemresource]データベース。また、[mssqlsystemresource]データベースには次の照合順序がありますLatin1_General_CI_AS_KS_WS

nameフィールドはのフィールドから取得さnamemaster.sys.sysdbregます。そのため、このフィールドは常に[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
  • containment_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)

これはどこで照合順序の優先順位がでてくるし始め、ここで出力のための両方のオプションは、システム関数です:。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です。どうして?さて、この式には新しいものが導入されています:実際のフィールドへの参照:[mssqlsystemresource].[sys].[syspalvalues].[name]その最後のELSE節。列参照は「暗黙的」と見なされます。

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

もちろん、これは興味深い質問を開きます:この式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

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

元の質問に戻る

観察された動作では、次のフィールドはサーバーの照合もデータベースの照合も観察しません。それらは常にLatin1_General_CI_AS_KS_WS照合順序で表示されます。

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

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

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

そして関連する質問:

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

それらが静的に設定されることも、他のフィールドが何らかの形で動的であることもありません。これらのすべてのシステムカタログビューのすべてのフィールドは、照合順序の同じルールで動作しています。それらが他のフィールドよりも「静的」であるように見える(つまり、デフォルトの照合を使用してシステムデータベースを作成する別のデフォルトの照合でSQL Serverをインストールしても変更されない)理由は、[mssqlsystemresource]データベースが一貫してLatin1_General_CI_AS_KS_WSSQL Serverのインストール全体の照合順序があります(または、確かに表示されます)。これは理にかなっています。さもないと、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クエリを実行したいようです」と言います。

Collat​​ion Precedenceとは何か、どのように機能するかがわかったので、その知識を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. 最初のエラーはCompatibilityLevelフィールドに関するもので、これはピボット解除される2番目のフィールドであり、たまたますべての文字列リテラルを含む式です。フィールド参照がない場合、結果の照合は「強制デフォルト」と見なされます)。強制デフォルトは、現在のデータベースの照合を引き継ぎますSQL_Latin1_General_CP1_CI_AS。次の20程度のフィールドも文字列リテラルのみであるため、強制的なデフォルトであるため、競合することはありません。我々は最初のフィールドに戻って見ればしかし、recovery_model_desc内のフィールドから直接来ているというsys.databasesこと「暗黙の」照合になり、これがないではないローカル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番目のテストでは、行った変更を元に戻す(つまりCOLLATECompatibilityLevel行の最後から句を削除する)必要があります。

    これで、SQL Serverがフィールドが指定された順序で本当に評価されている場合、フィールド1(RecoveryModel)を削除できます。これにより、現在のフィールド2(CompatibilityLevel)がマスター照合を設定するフィールドになります。結果のUNPIVOT。そして、CompatibilityLevelフィールドには、最初のエラーがでなければなりませんので、データベース照合にかかる強制可能-デフォルトでPageVerifyこのケースであり、元の照合、保持暗黙の照合であるフィールド参照、あるフィールド、Latin1_General_CI_AS_KS_WSおよびされていません現在のDBの照合。

    だから先に行くとラインアウトコメントで始まる, RecoveryModelSELECT(上に向かって)、その後、コメントアウトRecoveryModelの行をUNPIVOT以下の句とのために、次の行から先頭のカンマを削除CompatibilityLevelしますが、構文エラーを取得しないように。

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

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

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

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

    先に進み、次で始まる行の最後に追加します, RecoveryModelCOLLATE DATABASE_DEFAULT

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

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

    私たちは、この修正するために、今やらなければならないUNPIVOTクエリが追加することでCOLLATE DATABASE_DEFAULT、残りの暗黙の照合フィールドの最後に:PageVerifyRestrictedAccess。一方でCollation、フィールドでも暗黙の照合で、そのフィールドはから来てmaster、典型的には、「現在」のデータベースと一致しているデータベース、。ただし、これが常に機能するように安全にしたい場合COLLATE DATABASE_DEFAULTは、そのフィールドの最後にも追加してください。

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

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

    クエリを実行します。The type of column "X" conflicts with the type of other columns specified in the UNPIVOT list.一致しなかったのは照合のみであった場合と同じエラーを受け取るはずです。

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


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

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


5

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

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;

列の基本型に関する情報のために、3つの列を追加しましたOptionValue

サンプル出力

クライアントがsql_variantデータを処理できない場合、unpvt.OptionValue列で最終的な(トップレベル)変換を行いますnvarchar(256)


4

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

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';`
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.