Có gì với sự đối chiếu của một số cột trong sys.database?


21

Tôi đang cố gắng chạy một UNPIVOTcột khác nhau có trong sys.databasescác phiên bản khác nhau của SQL Server, từ năm 2005 đến 2012.

Các UNPIVOTlà không có thông báo lỗi sau:

Msg 8167, Cấp 16, Bang 1, Dòng 48

Loại cột "Tương thíchLevel" xung đột với loại cột khác được chỉ định trong danh sách 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;

Điều này được thiết kế để cung cấp một danh sách các tùy chọn cơ sở dữ liệu được định dạng độc đáo cho cơ sở dữ liệu đã cho, tương tự như:

+----------+----------------------------+----------------------------+
| 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 |
+----------+----------------------------+----------------------------+

Khi tôi chạy nó trong một máy chủ có Latin1_General_CI_AS_KS_WSđối chiếu, câu lệnh thành công. Nếu tôi sửa đổi T-SQL để các trường nhất định có COLLATEmệnh đề, nó sẽ chạy trên các máy chủ có các đối chiếu khác.

Mã hoạt động trên các máy chủ có các đối chiếu khác Latin1_General_CI_AS_KS_WSlà:

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;

Hành vi được quan sát là các trường sau không quan sát đối chiếu máy chủ hoặc đối chiếu cơ sở dữ liệu; chúng luôn được trình bày trong Latin1_General_CI_AS_KS_WSđối chiếu.

Trên SQL Server 2012, chúng tôi có thể sử dụng sys.sp_describe_first_result_setđể dễ dàng lấy siêu dữ liệu về các cột được trả về từ một truy vấn cụ thể. Tôi đã sử dụng như sau để xác định sự không phù hợp đối chiếu:

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;

Kết quả:

nhập mô tả hình ảnh ở đây

Tại sao đối chiếu của các cột này được đặt tĩnh?

Câu trả lời:


17

Từ chính thức từ Microsoft:

Một số cột chứa các chuỗi được xác định trước (như kiểu, mô tả hệ thống và hằng số) luôn được cố định cho một đối chiếu cụ thể - Latin1_General_CI_AS_KS_WS. Đây là bất kể đối chiếu đối tượng / cơ sở dữ liệu. Lý do là đây là siêu dữ liệu hệ thống (không phải siêu dữ liệu người dùng) và về cơ bản các chuỗi này được xử lý không phân biệt chữ hoa chữ thường (như từ khóa, vì vậy luôn luôn là tiếng Latin).

Các cột khác trong bảng hệ thống chứa siêu dữ liệu người dùng như tên đối tượng, tên cột, tên chỉ mục, tên đăng nhập, v.v ... lấy ví dụ hoặc đối chiếu cơ sở dữ liệu. Các cột được đối chiếu để đối chiếu thích hợp tại thời điểm cài đặt SQL Server trong trường hợp đối chiếu cá thể & tại thời điểm tạo cơ sở dữ liệu trong trường hợp đối chiếu cơ sở dữ liệu.

Bạn hỏi (nhấn mạnh của tôi):

Tại sao đối chiếu của các cột này được đặt tĩnh?

Lý do một số cột được đặt tĩnh là do các truy vấn không cần phải lo lắng về đối chiếu máy chủ hoặc cơ sở dữ liệu (quan trọng hơn: CaSe SenSiTIviTy) hoạt động chính xác. Truy vấn này sẽ luôn hoạt động bất kể đối chiếu:

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

Trong khi nếu đối chiếu máy chủ phân biệt chữ hoa chữ thường, truy vấn ở trên sẽ trả về 0 hàng, giống như thế này:

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

Ví dụ: nếu bạn cài đặt phiên bản SQL Server có SQL_Estonian_CP1257_CS_ASđối chiếu, thì hãy chạy như sau:

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

Bạn sẽ thấy những kết quả này (hoặc một cái gì đó tương tự, tùy thuộc vào phiên bản SQL Server của bạn):

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

Bây giờ, để chứng minh các chế độ xem siêu dữ liệu kế thừa đối chiếu cơ sở dữ liệu, thay vì kế thừa đối chiếu máy chủ từ cơ sở dữ liệu chủ:

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

Các kết quả:

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

Vì vậy, bạn có thể thấy rằng trong trường hợp này, một số cột kế thừa đối chiếu cơ sở dữ liệu, trong khi các cột khác được cố định với đối chiếu Latin1 "chung" này, có nghĩa là nó được sử dụng để cách ly một số tên và thuộc tính khỏi các vấn đề nhạy cảm trường hợp như mô tả ở trên.

Nếu bạn cố gắng thực hiện một UNION, ví dụ:

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

Bạn nhận được lỗi này:

Msg 451, Cấp 16, Trạng thái 1
Không thể giải quyết xung đột đối chiếu giữa "Albania_BIN" và "SQL_Estonian_CP1257_CS_AS" trong toán tử UNION ALL xảy ra trong cột câu lệnh SELECT 1.

Tương tự, nếu bạn cố gắng thực hiện một PIVOThoặc UNPIVOT, các quy tắc thậm chí còn chặt chẽ hơn (tất cả các loại đầu ra phải khớp chính xác thay vì chỉ tương thích), nhưng thông báo lỗi ít hữu ích hơn và thậm chí sai lệch:

Msg 8167, Cấp 16, Trạng thái 1
Loại cột "tên cột" xung đột với loại cột khác được chỉ định trong danh sách UNPIVOT.

Bạn cần xử lý các lỗi này bằng COLLATEcác mệnh đề rõ ràng trong các truy vấn của mình. Ví dụ: liên minh ở trên có thể là:

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;

Lần duy nhất điều này có thể gây ra sự cố là bạn sẽ nhận được đầu ra khó hiểu nếu đối chiếu bị ép buộc nhưng không chứa biểu diễn ký tự giống nhau hoặc nếu sắp xếp được sử dụng và đối chiếu cưỡng bức sử dụng thứ tự sắp xếp khác với nguồn.


7

Bối cảnh về Ưu tiên đối chiếu

Hành vi bạn đang thấy liên quan đến Đối chiếu các trường khác nhau trong chế độ xem danh mục hệ thống là kết quả của cách mỗi trường được xác định và Ưu tiên đối chiếu.

Khi nhìn vào sys.databases, điều quan trọng là phải nhớ rằng nó không phải là một cái bàn. Trong khi trước đây (tôi nghĩ kết thúc tại SQL Server 2000) đây là các bảng danh mục hệ thống , thì bây giờ chúng là các khung nhìn danh mục hệ thống . Do đó, nguồn thông tin trong chúng không nhất thiết phải đến từ bối cảnh cơ sở dữ liệu hiện tại (hoặc bối cảnh của cơ sở dữ liệu đã chỉ định khi xử lý một đối tượng đủ điều kiện nhưmaster.sys.databases ).

Đối phó cụ thể sys.databases, một số trường đến từ [master]cơ sở dữ liệu (được tạo bằng đối chiếu dựa trên đối chiếu mặc định của cá thể - tức là đối chiếu ở cấp độ máy chủ), một số trường là biểu thức (ví dụ: CASEcâu lệnh) và một số trường đang đến từ một nguồn "ẩn": [mssqlsystemresource]cơ sở dữ liệu. Và [mssqlsystemresource]cơ sở dữ liệu có đối chiếu : Latin1_General_CI_AS_KS_WS.

Các namelĩnh vực có nguồn gốc từ các namelĩnh vực trong master.sys.sysdbreg. Vì vậy, trường này phải luôn nằm trong đối chiếu [master]cơ sở dữ liệu, một lần nữa sẽ khớp với đối chiếu của máy chủ.

NHƯNG, các trường sau sys.databasesđến từ [name]trường trong [mssqlsystemresource].[sys].[syspalvalues]:

  • user_access_desc
  • snapshot_isolation_state_desc
  • recovery_model_desc
  • page_verify_option_desc
  • log_Vuse_wait_desc
  • ngăn chặn_desc

Những lĩnh vực phải luôn luôn có một đối chiếu Latin1_General_CI_AS_KS_WS.

Các collation_namelĩnh vực, tuy nhiên, xuất phát từ biểu thức sau đây:

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)

Đây là nơi Collation Precedence bắt đầu xuất hiện. Cả hai tùy chọn cho đầu ra ở đây là các chức năng hệ thống: serverproperty()collationpropertyfromid(). Đối chiếu của biểu thức này được coi là "Mặc định cưỡng chế":

Bất kỳ biến chuỗi ký tự Transact-SQL, tham số, bằng chữ hoặc đầu ra của hàm dựng sẵn trong danh mục hoặc hàm dựng sẵn không lấy đầu vào chuỗi mà tạo ra đầu ra chuỗi.

Nếu đối tượng được khai báo trong hàm do người dùng định nghĩa, thủ tục được lưu trữ hoặc kích hoạt, thì đối tượng được gán đối chiếu mặc định của cơ sở dữ liệu trong đó chức năng, thủ tục được lưu trữ hoặc kích hoạt được tạo. Nếu đối tượng được khai báo theo lô, thì đối tượng được gán đối chiếu mặc định của cơ sở dữ liệu hiện tại cho kết nối.

Trong đoạn thứ 2 đó, vì sys.databaseslà một khung nhìn tồn tại trong mastercơ sở dữ liệu, nên nó sẽ đối chiếu mastercơ sở dữ liệu (không phải cơ sở dữ liệu hiện tại).

Trường state_desccũng là một biểu thức:

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

Nhưng, đối chiếu trên biểu thức này là Latin1_General_CI_AS_KS_WS. Tại sao? Vâng, một cái gì đó mới được giới thiệu trong biểu thức này: một tham chiếu đến một trường thực: [mssqlsystemresource].[sys].[syspalvalues].[name]trong ELSEmệnh đề cuối cùng đó . Tham chiếu cột được coi là "tiềm ẩn":

Một tài liệu tham khảo cột. Đối chiếu của biểu thức được lấy từ đối chiếu được xác định cho cột trong bảng hoặc dạng xem.

Tất nhiên, điều này mở ra một câu hỏi thú vị: biểu thức này có thể trả về một đối chiếu khác nhau tùy thuộc vào cách CASEđánh giá không? Các chữ sẽ nằm trong đối chiếu của cơ sở dữ liệu nơi đối tượng này được xác định, nhưng ELSEđiều kiện trả về một giá trị trường sẽ giữ lại đối chiếu ban đầu của nó. May mắn thay, chúng ta có thể mô phỏng thử nghiệm bằng sys.dm_exec_describe_first_result_set Chức năng quản lý động:

-- 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

Trả về (trên một cá thể được thiết lập với đối chiếu SQL_Latin1_General_CP1_CI_ASnhưng đang chạy trong cơ sở dữ liệu có đối chiếu 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

Ở đây chúng ta thấy rằng hai truy vấn tham chiếu trường [msdb]tham gia vào đối chiếu của[msdb] cơ sở dữ liệu (là DB hệ thống, được xác định bởi đối chiếu máy chủ).

Liên quan đến câu hỏi ban đầu

Hành vi được quan sát là các trường sau không quan sát đối chiếu máy chủ hoặc đối chiếu cơ sở dữ liệu; chúng luôn được trình bày trong Latin1_General_CI_AS_KS_WSđối chiếu.

Quan sát của bạn là tại chỗ: các trường đó luôn có đối chiếu Latin1_General_CI_AS_KS_WS, bất kể đối chiếu máy chủ hoặc đối chiếu cơ sở dữ liệu. Và lý do là: Ưu tiên đối chiếu. Các trường đó đến từ một bảng trong [mssqlsystemresource]cơ sở dữ liệu và sẽ giữ lại đối chiếu ban đầu đó trừ khi được ghi đè bằng một COLLATEmệnh đề rõ ràng vì đó có quyền ưu tiên cao nhất:

Explicit = Một biểu thức được truyền rõ ràng cho một đối chiếu cụ thể bằng cách sử dụng mệnh đề COLLATE trong biểu thức.

Rõ ràng được ưu tiên hơn ngầm. Ngẫu nhiên được ưu tiên hơn so với Coercible-default:
Explicit> Implicit> Coercible-default

Và câu hỏi liên quan:

Tại sao đối chiếu của các cột này được đặt tĩnh?

Không phải là chúng được đặt tĩnh, cũng không phải các trường khác là động. Tất cả các trường trong tất cả các chế độ xem danh mục hệ thống đều hoạt động theo cùng một quy tắc của Ưu tiên đối chiếu. Lý do chúng có vẻ "tĩnh" hơn các trường khác (nghĩa là chúng không thay đổi ngay cả khi bạn cài đặt SQL Server với đối chiếu mặc định khác, từ đó tạo ra cơ sở dữ liệu hệ thống với đối chiếu mặc định đó) là [mssqlsystemresource]cơ sở dữ liệu nhất quán có một đối chiếu Latin1_General_CI_AS_KS_WStrên bất kỳ cài đặt SQL Server nào (hoặc do đó chắc chắn nó sẽ xuất hiện). Và điều này có ý nghĩa bởi vì nếu không, SQL Server sẽ khó quản lý nội bộ (tức là nếu các quy tắc sắp xếp và so sánh được sử dụng cho logic bên trong thay đổi dựa trên cài đặt).

Làm thế nào để xem những chi tiết cụ thể cho mình

Nếu bạn muốn xem nguồn của bất kỳ trường nào trong bất kỳ chế độ xem danh mục hệ thống nào, chỉ cần làm như sau:

  1. Trong tab truy vấn trong SSMS, bật Tùy chọn truy vấn của "Bao gồm kế hoạch thực hiện thực tế" ( CTRL-M)
  2. Thực hiện truy vấn chọn một trường từ một trong các chế độ xem danh mục hệ thống (Tôi khuyên bạn chỉ nên chọn một trường tại một thời điểm vì kế hoạch thực hiện rất lớn / phức tạp cho dù chỉ một trường và sẽ bao gồm các tham chiếu đến nhiều trường mà bạn phát sinh ' chọn t)

    SELECT recovery_model_desc FROM sys.databases;
  3. Chuyển đến tab "Kế hoạch thực hiện"
  4. Nhấp chuột phải vào khu vực kế hoạch Thực hiện đồ họa và chọn "Hiển thị XML Kế hoạch thực hiện ..."
  5. Một tab mới trong SSMS sẽ mở ra với một tiêu đề tương tự như: Execution plan.xml
  6. Chuyển đến Execution plan.xmltab
  7. Hãy tìm sự xuất hiện đầu tiên của <OutputList>thẻ (thường là giữa các dòng 10 và 20)
  8. Cần có một <ColumnReference>thẻ. Các thuộc tính trong thẻ đó phải trỏ đến một trường cụ thể trong bảng hoặc trỏ đến một biểu thức được xác định sau trong kế hoạch.
  9. Nếu các thuộc tính trỏ đến một trường thực thì bạn đã hoàn thành vì nó có tất cả các thông tin. Sau đây là những gì hiển thị cho các recovery_model_desclĩnh vực:

    <ColumnReference Database="[mssqlsystemresource]" Schema="[sys]"
                     Table="[syspalvalues]" Alias="[ro]" Column="name" />
  10. Nếu các thuộc tính trỏ đến một biểu thức, chẳng hạn như nếu bạn thay vào đó chọn state_desctrường, thì ban đầu bạn sẽ tìm thấy:

    <ColumnReference Column="Expr1024" />
  11. Trong trường hợp này, bạn cần xem qua phần còn lại của kế hoạch để định nghĩa Expr1024hoặc bất cứ điều gì # nó đưa ra. Chỉ cần lưu ý rằng có thể có một vài trong số các tài liệu tham khảo này, nhưng định nghĩa sẽ không nằm trong một <OutputList>khối. Tuy nhiên, nó sẽ có một <ScalarOperator>yếu tố anh chị em có chứa định nghĩa. Sau đây là những gì hiển thị cho các state_desclĩnh vực:

    <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">

Điều tương tự cũng có thể được thực hiện để kiểm tra nguồn của các khung nhìn danh mục cấp cơ sở dữ liệu. Làm điều này cho một đối tượng như thế sys.tablessẽ cho thấy nametrường xuất phát [current_db].[sys].[sysschobjs](đó là lý do tại sao nó có đối chiếu khớp với đối chiếu của cơ sở dữ liệu), trong khi lock_escalation_desctrường xuất phát [mssqlsystemresource].[sys].[syspalvalues](đó là lý do tại sao nó có đối chiếu Latin1_General_CI_AS_KS_WS).

Clippy nói, "Có vẻ như bạn muốn thực hiện một truy vấn UNPIVOT."

Bây giờ chúng ta đã biết tại sao Collation Preedence là gì và nó hoạt động như thế nào, hãy áp dụng kiến ​​thức đó vào truy vấn UNPIVOT.

Đối với một UNPIVOThoạt động, SQL Server dường như thực sự thích (nghĩa là: yêu cầu) rằng mỗi trường nguồn phải cùng loại . Thông thường "loại" dùng để chỉ loại cơ sở (tức là VARCHAR/ NVARCHAR/ INT/ etc) nhưng ở đây SQL Server cũng bao gồm cả THU. Điều này không nên được coi là không hợp lý khi đưa ra điều khiển Collations: bộ ký tự (tức là Trang mã) cho VARCHAR và các quy tắc ngôn ngữ xác định sự tương đương của các ký tự và kết hợp các ký tự (nghĩa là chuẩn hóa). Sau đây là một mimi-primer về "chuẩn hóa" Unicode là gì:

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 '---';

Trả về:

---
Danish_Greenlandic_100_CI_AI
---
Upper_Sorbian_100_CI_AI
---

Vì vậy, bây giờ hãy bắt đầu truy vấn ban đầu của bạn. Chúng tôi sẽ thực hiện một vài thử nghiệm để xem các thay đổi khác nhau thay đổi kết quả như thế nào và sau đó chúng tôi sẽ xem chỉ một vài thay đổi có thể khắc phục nó.

  1. Lỗi đầu tiên là về CompatibilityLeveltrường, đó là trường thứ hai không được xoay vòng và tình cờ là một biểu thức có chứa tất cả các chuỗi ký tự. Không có tham chiếu trường, đối chiếu kết quả được coi là "mặc định cưỡng chế"). Mặc định cưỡng chế đảm nhận việc đối chiếu cơ sở dữ liệu hiện tại, giả sử SQL_Latin1_General_CP1_CI_AS. 20 trường tiếp theo cũng chỉ là chuỗi ký tự và do đó cũng là mặc định cưỡng chế, vì vậy chúng không nên xung đột. Nhưng nếu chúng ta nhìn lại trường đầu tiên recovery_model_desc, nó xuất phát trực tiếp từ một trường trong sys.databasesđó làm cho nó đối chiếu "ngầm" và điều này không thực hiện đối chiếu của DB cục bộ, mà thay vào đó vẫn giữ nguyên đối chiếu ban đầu, đó là Latin1_General_CI_AS_KS_WS( bởi vì nó thực sự đến từ [mssqlsystemresource]DB).

    Vì vậy, nếu trường 1 (RecoveryModel) là Latin1_General_CI_AS_KS_WSvà trường 2 (CompabilitiesLevel) SQL_Latin1_General_CP1_CI_AS, thì chúng ta sẽ có thể buộc trường 2 Latin1_General_CI_AS_KS_WSphải khớp với trường 1, và sau đó lỗi sẽ xuất hiện cho trường 3 (Tự động đóng).

    Thêm dòng sau vào cuối CompatibilityLeveldòng:
    COLLATE Latin1_General_CI_AS_KS_WS

    Và sau đó chạy truy vấn. Chắc chắn, lỗi bây giờ nói rằng đó là AutoCloselĩnh vực có xung đột.

  2. Đối với thử nghiệm thứ hai của chúng tôi, chúng tôi cần hoàn tác thay đổi mà chúng tôi vừa thực hiện (nghĩa là xóa COLLATEmệnh đề khỏi cuối CompatibilityLeveldòng.

    Bây giờ, nếu SQL Server thực sự đánh giá theo thứ tự các trường được chỉ định, chúng ta sẽ có thể xóa trường 1 (RecoveryModel), điều này sẽ khiến trường hiện tại 2 (CompabilitiesLevel) trở thành trường đặt đối chiếu chính của kết quả UNPIVOT. Và CompatibilityLeveltrường là một mặc định cưỡng chế, trong đó đối chiếu cơ sở dữ liệu, do đó, lỗi đầu tiên phải là PageVerifytrường, là tham chiếu trường, là đối chiếu ngầm giữ lại đối chiếu ban đầu, trong trường hợp này là Latin1_General_CI_AS_KS_WSvà không phải là đối chiếu của DB hiện tại.

    Vì vậy, đi trước và nhận xét ra các dòng bắt đầu với , RecoveryModeltrong SELECT(phía trên cùng) và sau đó nhận xét ra các RecoveryModeldòng trong UNPIVOTđiều khoản dưới đây và loại bỏ các dấu phẩy hàng đầu từ dòng sau đây để CompatibilityLevelsao cho bạn không nhận được một lỗi cú pháp.

    Chạy truy vấn đó. Chắc chắn, lỗi bây giờ nói rằng đó là PageVerifylĩnh vực có xung đột.

  3. Đối với thử nghiệm thứ ba của chúng tôi, chúng tôi cần hoàn tác các thay đổi chúng tôi vừa thực hiện để xóa RecoveryModeltrường. Vì vậy, đi trước và đặt lại dấu phẩy, và bỏ qua hai dòng khác.

    Bây giờ chúng ta có thể đi theo hướng khác với việc buộc đối chiếu. Thay vì thay đổi đối chiếu các trường đối chiếu mặc định cưỡng chế (phần lớn trong số chúng), chúng ta sẽ có thể thay đổi các trường đối chiếu ngầm thành trường DB hiện tại, phải không?

    Vì vậy, giống như thử nghiệm đầu tiên của chúng tôi, chúng tôi sẽ có thể buộc đối chiếu trường 1 (RecoveryModel) bằng một COLLATEmệnh đề rõ ràng . Nhưng nếu chúng ta chỉ định một đối chiếu cụ thể và sau đó chạy truy vấn trong cơ sở dữ liệu với đối chiếu khác nhau, các trường đối chiếu mặc định cưỡng chế sẽ chọn đối chiếu mới, sau đó sẽ xung đột với trường chúng ta đang đặt trường đầu tiên này. Đó dường như là một nỗi đau. May mắn thay, có một cách năng động để đối phó với điều này. Có một đối chiếu giả được gọi là đối chiếu DATABASE_DEFAULTcơ sở dữ liệu đối chiếu hiện tại (giống như các trường mặc định cưỡng chế làm).

    Đi trước và thêm phần sau vào cuối dòng, về phía trên, bắt đầu bằng , RecoveryModel: COLLATE DATABASE_DEFAULT

    Chạy truy vấn đó. Chắc chắn, các trạng thái lỗi, một lần nữa, đó là PageVerifylĩnh vực có xung đột.

  4. Đối với thử nghiệm cuối cùng, chúng tôi không cần hoàn tác bất kỳ thay đổi nào trước đó.

    Tất cả những gì chúng ta cần làm bây giờ để khắc phục UNPIVOTtruy vấn này là thêm COLLATE DATABASE_DEFAULTvào cuối các trường đối chiếu ẩn còn lại: PageVerifyRestrictedAccess. Mặc dù Collationtrường cũng là một đối chiếu ngầm, trường đó xuất phát từ mastercơ sở dữ liệu, thường phù hợp với cơ sở dữ liệu "hiện tại". Nhưng, nếu bạn muốn an toàn để điều này luôn hoạt động, thì hãy tiếp tục thêm COLLATE DATABASE_DEFAULTphần cuối của trường đó.

    Chạy truy vấn đó. Chắc chắn, không có lỗi. Tất cả những gì cần thiết để khắc phục truy vấn này là thêm COLLATE DATABASE_DEFAULTvào cuối 3 trường (bắt buộc) và có thể thêm 1 (tùy chọn).

  5. Kiểm tra tùy chọn: Bây giờ cuối cùng chúng ta cũng có truy vấn UNPIVOT hoạt động chính xác, chỉ thay đổi một trong các định nghĩa trường bắt đầu bằng CONVERT(VARCHAR(50),thay vào đó 51, như trong : CONVERT(VARCHAR(51),.

    Chạy truy vấn. Bạn sẽ nhận được cùng một The type of column "X" conflicts with the type of other columns specified in the UNPIVOT list.lỗi mà bạn gặp phải khi đó chỉ là đối chiếu không khớp.

    Nhận cùng một lỗi cho cả hai kiểu dữ liệu và đối chiếu không phù hợp là không đủ cụ thể để thực sự hữu ích. Vì vậy, chắc chắn có chỗ để cải thiện đó :).


Lưu ý liên quan đến Truy vấn nhiều hơn Câu hỏi cụ thể về Đối chiếu:

Vì tất cả các trường nguồn là của kiểu dữ liệu NVARCHAR, nên sẽ an toàn hơn cho CONVERTtất cả các trường đầu ra NVARCHARthay vì VARCHAR. Bạn có thể không xử lý dữ liệu tại thời điểm có bất kỳ ký tự ASCII không chuẩn nào, nhưng dữ liệu meta hệ thống cho phép chúng chuyển đổi thành NVARCHAR(128)- có độ dài tối đa lớn nhất trong số các trường đó - ít nhất là đảm bảo rằng sẽ không có vấn đề gì với bạn trong tương lai hoặc cho bất kỳ ai khác sao chép mã này, những người có thể đã có một số các ký tự đó trong hệ thống của họ.


5

Đây là một cách giải quyết cho vấn đề cụ thể chứ không phải là một câu trả lời đầy đủ cho câu hỏi. Bạn có thể tránh lỗi bằng cách chuyển đổi sang sql_variantthay vì 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;

Tôi đã thêm ba cột để biết thông tin về loại cơ bản của OptionValuecột.

Sản lượng mẫu

Nếu khách hàng không thể xử lý sql_variantdữ liệu, hãy thực hiện chuyển đổi cuối cùng (cấp cao nhất) trên unpvt.OptionValuecột, vd nvarchar(256).


4

Ok, vì vậy tôi đã xem

sp_helptext [sys.databases]

sau đó phá vỡ nơi các cột đến từ. Tất cả những cái có Latin1_General_CI_AS_KS_WSđối chiếu đều xuất phát từ bảng hệ thống sys.syspalvaluesdường như là bảng tra cứu chung (đó là bảng hệ thống, vì vậy bạn sẽ phải kết nối qua DAC để xem nó.).

Tôi đoán là nó được thiết lập Latin1_General_CI_AS_KS_WSđể xử lý bất kỳ giá trị tra cứu nào có thể. Tôi có thể thấy nó sẽ gây phiền nhiễu như thế nào.

Một cách khác để xem định nghĩa (ban đầu được cung cấp bởi Max trong một nhận xét) là:

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';`
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.