Was ist los mit der Sortierung einiger Spalten in sys.databases?


21

Ich versuche, ein UNPIVOTauf verschiedenen Spalten auszuführen , die in enthalten sindsys.databases verschiedenen Versionen von SQL Server von 2005 bis 2012 .

Das UNPIVOTschlägt mit der folgenden Fehlermeldung fehl:

Nachricht 8167, Ebene 16, Status 1, Zeile 48

Der Spaltentyp "CompatibilityLevel" steht in Konflikt mit dem Typ anderer Spalten, die in der UNPIVOT-Liste angegeben sind.

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

Dies wurde entwickelt, um eine gut formatierte Liste von Datenbankoptionen für die angegebene Datenbank bereitzustellen, ähnlich wie:

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

Wenn ich dies auf einem Server mit Latin1_General_CI_AS_KS_WSSortierung ausführe , ist die Anweisung erfolgreich. Wenn ich das T-SQL so ändere, dass bestimmte Felder eine COLLATEKlausel enthalten, wird es auf Servern mit anderen Sortierungen ausgeführt.

Der Code, der auf Servern mit anderen Sortierungen als funktioniert, Latin1_General_CI_AS_KS_WSlautet:

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;

Das beobachtete Verhalten besteht darin, dass die folgenden Felder weder die Server-Kollatierung noch die Datenbank-Kollatierung beobachten. Sie werden immer in Latin1_General_CI_AS_KS_WSKollation dargestellt.

Unter SQL Server 2012 können wir sys.sp_describe_first_result_setauf einfache Weise Metadaten zu den von einer bestimmten Abfrage zurückgegebenen Spalten abrufen. Ich habe Folgendes verwendet, um die Kollatierungsinkongruenz zu bestimmen:

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;

Die Ergebnisse:

Bildbeschreibung hier eingeben

Warum ist die Sortierung dieser Spalten statisch festgelegt?

Antworten:


17

Das offizielle Wort von Microsoft:

Einige der Spalten, die vordefinierte Zeichenfolgen enthalten (z. B. Typen, Systembeschreibungen und Konstanten), sind immer auf eine bestimmte Sortierung festgelegt Latin1_General_CI_AS_KS_WS. Dies ist unabhängig von der Instanz- / Datenbanksortierung. Der Grund dafür ist, dass dies Systemmetadaten sind (keine Benutzermetadaten), und im Grunde werden diese Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung behandelt (wie Schlüsselwörter, also immer lateinisch).

Andere Spalten in Systemtabellen, die Benutzermetadaten wie Objektnamen, Spaltennamen, Indexnamen, Anmeldenamen usw. enthalten, verwenden die Instanz- oder Datenbanksortierung. Die Spalten werden zum Zeitpunkt der Installation von SQL Server im Falle einer Instanzkollatierung und zum Zeitpunkt der Erstellung der Datenbank im Falle einer Datenbankkollatierung auf die richtige Kollatierung sortiert.

Sie fragten (Schwerpunkt meiner):

Warum ist die Sortierung dieser Spalten statisch festgelegt?

Der Grund, warum einige Spalten statisch festgelegt sind, besteht darin, dass Abfragen sich nicht um die Sortierung von Servern oder Datenbanken kümmern müssen (was noch wichtiger ist: SenSiTIviTy überprüfen), um ordnungsgemäß zu funktionieren. Diese Abfrage funktioniert unabhängig von der Sortierung immer:

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

Wäre bei der Sortierung des Servers die Groß- und Kleinschreibung zu beachten, würde die obige Abfrage 0 Zeilen zurückgeben, genau wie dies der Fall ist:

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

Wenn Sie beispielsweise eine Instanz von SQL Server mit SQL_Estonian_CP1257_CS_ASSortierung installieren , führen Sie Folgendes aus:

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

Sie sehen die folgenden Ergebnisse (oder etwas Ähnliches, abhängig von Ihrer Version von 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

Gehen Sie wie folgt vor, um Metadatenansichten zu veranschaulichen, die die Datenbanksortierung übernehmen, anstatt die Server-Sortierung von der master-Datenbank zu übernehmen:

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

Ergebnisse:

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

Sie können also sehen, dass in diesem Fall mehrere Spalten die Datenbanksortierung erben, während andere auf diese "generische" Latin1-Sortierung festgelegt sind. Dies bedeutet, dass bestimmte Namen und Eigenschaften wie oben beschrieben von Problemen mit der Groß- und Kleinschreibung isoliert werden.

Wenn Sie versuchen, eine auszuführen UNION, zum Beispiel:

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

Sie erhalten diesen Fehler:

Meldung 451, Ebene 16,
Status 1 Der Kollatierungskonflikt zwischen "Albanian_BIN" und "SQL_Estonian_CP1257_CS_AS" im UNION ALL-Operator in der SELECT-Anweisungsspalte 1 kann nicht aufgelöst werden.

Wenn Sie versuchen, ein PIVOToder auszuführen UNPIVOT, sind die Regeln noch strenger (die Ausgabetypen müssen alle genau übereinstimmen , anstatt nur kompatibel zu sein), aber die Fehlermeldung ist weitaus weniger hilfreich und sogar irreführend:

Meldung 8167, Ebene 16,
Status 1 Der Spaltentyp "Spaltenname" steht im Konflikt mit dem Typ anderer Spalten, die in der UNPIVOT-Liste angegeben sind.

Sie müssen diese Fehler mit expliziten COLLATEKlauseln in Ihren Abfragen umgehen. Die obige Vereinigung könnte beispielsweise sein:

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;

Dies kann nur zu Problemen führen, wenn die Ausgabe verwirrend ist, wenn eine Sortierung erzwungen wird, aber nicht die gleiche Zeichendarstellung enthält, oder wenn die Sortierung verwendet wird und die erzwungene Sortierung eine andere Sortierreihenfolge als die Quelle verwendet.


7

Hintergrundinformationen zur Rangfolge

Das Verhalten, das Sie in Bezug auf die Sortierung verschiedener Felder in den Systemkatalogansichten sehen, ist das Ergebnis der Definition der einzelnen Felder und der Rangfolge der Sortierungen.

Beim Betrachten sys.databasesist zu beachten, dass es sich nicht um einen Tisch handelt. Während in der Vergangenheit (ich glaube , bei SQL Server 2000 endet) waren diese Systemkatalogtabellen , sie jetzt Systemkatalog sind Ansichten . Daher stammt die Quelle der darin enthaltenen Informationen nicht unbedingt aus dem aktuellen Datenbankkontext (oder dem Kontext der angegebenen Datenbank, wenn es sich um ein vollständig qualifiziertes Objekt handelt, z. B. master.sys.databases).

Der Umgang speziell mit sys.databases, einige der Felder aus der kommen - [master]Datenbank (die mit einer Zusammenstellung erstellt wurde , auf der Grundlage der Standardsortierung der Instanz - dh auf Serverebene Sortierungs), einige der Felder sind Ausdrücke (dh CASEAnweisungen), und einige kommen aus einer "versteckten" Quelle: die [mssqlsystemresource]Datenbank. Und die [mssqlsystemresource]Datenbank hat eine Zusammenstellung von:Latin1_General_CI_AS_KS_WS .

Das nameFeld wird vom nameFeld in bezogen master.sys.sysdbreg. Dieses Feld sollte sich also immer in der Zusammenstellung von befinden[master] Datenbank befinden, die wiederum mit der Kollatierung des Servers übereinstimmt.

ABER die folgenden Felder sys.databasesstammen aus dem [name]Feld in [mssqlsystemresource].[sys].[syspalvalues]:

  • user_access_desc
  • snapshot_isolation_state_desc
  • recovery_model_desc
  • page_verify_option_desc
  • log_reuse_wait_desc
  • containment_desc

Diese Felder sollten immer eine Sortierung von haben Latin1_General_CI_AS_KS_WS .

Das collation_nameFeld stammt jedoch aus dem folgenden Ausdruck:

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)

Hier setzt die Sortierfolge an. Beide Optionen für die Ausgabe sind Systemfunktionen: serverproperty()und collationpropertyfromid(). Die Kollation dieses Ausdrucks wird als "Coercible-Standard" betrachtet:

Alle Transact-SQL-Zeichenfolgenvariablen, -Parameter, -Literalen oder die Ausgabe einer integrierten Katalogfunktion oder einer integrierten Funktion, die keine Zeichenfolgeneingaben entgegennimmt, sondern eine Zeichenfolgenausgabe erzeugt.

Wenn das Objekt in einer benutzerdefinierten Funktion, einer gespeicherten Prozedur oder einem Trigger deklariert wird, wird dem Objekt die Standardkollatierung der Datenbank zugewiesen, in der die Funktion, die gespeicherte Prozedur oder der Trigger erstellt werden. Wenn das Objekt in einem Stapel deklariert ist, wird dem Objekt die Standardkollatierung der aktuellen Datenbank für die Verbindung zugewiesen.

Da sys.databaseses sich um eine in der masterDatenbank vorhandene Ansicht handelt, wird in Anbetracht des zweiten Absatzes die Sortierung der masterDatenbank (nicht der aktuellen Datenbank) übernommen.

Das state_descFeld ist auch ein Ausdruck:

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

Die Zusammenstellung dieses Ausdrucks ist jedoch Latin1_General_CI_AS_KS_WS. Warum? Nun, in diesem Ausdruck wird etwas Neues eingeführt: ein Verweis auf ein reales Feld: [mssqlsystemresource].[sys].[syspalvalues].[name]in diesem Schlusssatz ELSE. Spaltenverweise gelten als "implizit":

Eine Spaltenreferenz. Die Sortierung des Ausdrucks wird aus der Sortierung übernommen, die für die Spalte in der Tabelle oder Ansicht definiert ist.

Dies wirft natürlich eine interessante Frage auf: Kann dieser Ausdruck eine andere Kollatierung zurückgeben, je nachdem, wie die CASEausgewertet wird? Die Literale befinden sich in der Kollatierung der Datenbank, in der dieses Objekt definiert ist. Die ELSEBedingung gibt jedoch einen Feldwert zurück, der die ursprüngliche Kollatierung beibehalten soll. Glücklicherweise können wir einen Test mit der Dynamic Management Function sys.dm_exec_describe_first_result_set simulieren :

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

Rückgabe (für eine Instanz, die mit einer Kollatierung von eingerichtet wurde, SQL_Latin1_General_CP1_CI_ASjedoch in einer Datenbank mit einer Kollatierung von ausgeführt wird 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

Hier sehen wir, dass die beiden Abfragen, die auf das Feld in verweisen [msdb], die Sortierung von übernehmen[msdb] Datenbank übernehmen (die als System-DB durch die Server-Sortierung bestimmt wurde).

Auf die ursprüngliche Frage zurückkommen

Das beobachtete Verhalten besteht darin, dass die folgenden Felder weder die Server-Kollatierung noch die Datenbank-Kollatierung beobachten. Sie werden immer in Latin1_General_CI_AS_KS_WSKollation dargestellt.

Ihre Beobachtung ist genau richtig: Diese Felder haben immer eine Sortierung von Latin1_General_CI_AS_KS_WS, unabhängig von der Server- oder Datenbanksortierung. Und der Grund ist: Vorrang für die Sortierung. Diese Felder stammen aus einer Tabelle in der [mssqlsystemresource]Datenbank und behalten diese ursprüngliche Sortierung bei, sofern sie nicht mit einer expliziten COLLATEKlausel überschrieben werden , da diese die höchste Priorität hat:

Explicit = Ein Ausdruck, der mithilfe einer COLLATE-Klausel im Ausdruck explizit in eine bestimmte Kollatierung umgewandelt wird.

Explizit hat Vorrang vor Implizit. Implizit hat Vorrang vor Coercible-Standard:
Explizit> Implizit> Coercible-Standard

Und die dazugehörige Frage:

Warum ist die Sortierung dieser Spalten statisch festgelegt?

Es ist nicht so, dass sie statisch festgelegt sind, noch dass die anderen Felder irgendwie dynamisch sind. Alle Felder in all diesen Systemkatalogansichten unterliegen denselben Regeln für die Rangfolge. Der Grund dafür, dass sie "statischer" zu sein scheinen als die anderen Felder (dh sie ändern sich nicht, selbst wenn Sie SQL Server mit einer anderen Standardsortierung installieren, wodurch wiederum die Systemdatenbanken mit dieser Standardsortierung erstellt werden), ist, dass die [mssqlsystemresource]Datenbank konsistent ist hat eine Sortierung von Latin1_General_CI_AS_KS_WSüber jede Installation von SQL Server (oder so scheint es sicherlich). Dies ist sinnvoll, da sich SQL Server ansonsten nur schwer selbst verwalten lässt (dh wenn sich die für die interne Logik verwendeten Sortier- und Vergleichsregeln aufgrund der Installation ändern).

Wie Sie diese Details selbst sehen können

Wenn Sie die Quelle eines oder mehrerer Felder in einer dieser Systemkatalogansichten anzeigen möchten, gehen Sie wie folgt vor:

  1. Aktivieren Sie auf einer Abfrage-Registerkarte in SSMS die Abfrageoption "Aktuellen Ausführungsplan einbeziehen" ( CTRL-M).
  2. Ausführen einer Abfrage, die ein Feld aus einer der Systemkatalogansichten auswählt (ich empfehle, jeweils nur ein Feld auszuwählen, da der Ausführungsplan für nur ein einziges Feld lächerlich umfangreich / komplex ist und Verweise auf viele Felder enthält, die Sie nicht haben). t auswählen):

    SELECT recovery_model_desc FROM sys.databases;
  3. Gehen Sie zur Registerkarte "Ausführungsplan"
  4. Klicken Sie mit der rechten Maustaste in den grafischen Ausführungsplanbereich und wählen Sie "Ausführungsplan-XML anzeigen ...".
  5. In SSMS wird eine neue Registerkarte mit einem Titel wie dem folgenden geöffnet: Execution plan.xml
  6. Gehen Sie zur Execution plan.xmlRegisterkarte
  7. Suchen Sie nach dem ersten Vorkommen eines <OutputList>Tags (es sollte normalerweise zwischen den Zeilen 10 und 20 liegen)
  8. Es sollte ein <ColumnReference>Tag geben. Die Attribute in diesem Tag sollten entweder auf ein bestimmtes Feld in einer Tabelle oder auf einen später im Plan definierten Ausdruck verweisen.
  9. Wenn die Attribute auf ein reales Feld verweisen, sind Sie fertig, da es alle Informationen enthält. Folgendes zeigt sich für das recovery_model_descFeld:

    <ColumnReference Database="[mssqlsystemresource]" Schema="[sys]"
                     Table="[syspalvalues]" Alias="[ro]" Column="name" />
  10. Wenn die Attribute auf einen Ausdruck verweisen, z. B. wenn Sie stattdessen das state_descFeld ausgewählt haben , finden Sie zunächst Folgendes:

    <ColumnReference Column="Expr1024" />
  11. In diesem Fall müssen Sie den Rest des Plans nach der Definition von Expr1024oder was auch immer durchsehen. Denken Sie daran, dass es mehrere dieser Referenzen geben kann, die Definition jedoch nicht in einem <OutputList>Block enthalten ist. Es wird jedoch ein <ScalarOperator>Geschwisterelement enthalten, das die Definition enthält. Folgendes zeigt sich für das state_descFeld:

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

Das Gleiche gilt für die Überprüfung der Quelle von Katalogansichten auf Datenbankebene. Wenn Sie dies für ein Objekt wie tun, sys.tableswird angezeigt, dass das nameFeld von stammt [current_db].[sys].[sysschobjs](weshalb es eine Kollatierung hat, die mit der Kollatierung der Datenbank übereinstimmt), während das lock_escalation_descFeld von stammt [mssqlsystemresource].[sys].[syspalvalues](weshalb es eine Kollatierung von hat Latin1_General_CI_AS_KS_WS).

Clippy sagt: "Es sieht so aus, als ob Sie eine UNPIVOT-Abfrage durchführen möchten."

Nachdem wir nun wissen, warum und wie die Kollatierungsrangfolge funktioniert, wenden wir dieses Wissen auf die UNPIVOT-Abfrage an.

Für eine UNPIVOTOperation scheint SQL Server wirklich zu bevorzugen (was bedeutet: erfordert), dass jedes Quellfeld vom exakt gleichen Typ ist . Normalerweise bezieht sich "Typ" auf den Basistyp (dh VARCHAR/ NVARCHAR/ INT/ etc), aber hier enthält SQL Server auch die COLLATION. Dies sollte nicht als unzumutbar angesehen werden, da Kollatierungen Folgendes steuern: den Zeichensatz (dh die Codepage) für VARCHAR und die Sprachregeln, die die Gleichwertigkeit von Zeichen und Zeichenkombinationen bestimmen (dh die Normalisierung). Das Folgende ist ein Mimi-Primer zu dem, was Unicode "Normalisierung" ist:

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

Kehrt zurück:

---
Danish_Greenlandic_100_CI_AI
---
Upper_Sorbian_100_CI_AI
---

Beginnen wir nun mit Ihrer ursprünglichen Abfrage. Wir werden ein paar Tests durchführen, um zu sehen, wie verschiedene Änderungen das Ergebnis verändern, und dann werden wir sehen, wie nur ein paar Änderungen es beheben können.

  1. Der erste Fehler CompatibilityLevelbetrifft das Feld, bei dem es sich um das zweite Feld handelt, bei dem es sich nicht um ein Pivot-Feld handelt, sondern um einen Ausdruck, der alle Zeichenfolgenliterale enthält. Ohne Feldverweise wird die resultierende Kollation als "Coercible-Default" bezeichnet. Die Standardeinstellungen für die Zwangsumsetzung übernehmen beispielsweise die Sortierung der aktuellen Datenbank SQL_Latin1_General_CP1_CI_AS. Die nächsten 20 Felder sind ebenfalls nur Zeichenfolgenliterale und daher auch Standardwerte, sodass sie nicht in Konflikt stehen sollten. Aber wenn wir auf das erste Feld zurückblicken, recovery_model_desc, das direkt aus einem Feld kommt sys.databases, das es sich um einen „impliziten“ Sortierungs macht, und das ist nicht übernimmt die örtliche Sortierungs der DB, sondern behält seine ursprüngliche Zusammenstellung, das ist Latin1_General_CI_AS_KS_WS( weil es wirklich von der [mssqlsystemresource]DB kommt).

    Wenn also Feld 1 (RecoveryModel) Latin1_General_CI_AS_KS_WSund Feld 2 (CompatibilityLevel) ist SQL_Latin1_General_CP1_CI_AS, sollten wir Feld 2 zwingen können Latin1_General_CI_AS_KS_WS, mit Feld 1 übereinzustimmen, und dann sollte der Fehler für Feld 3 (AutoClose) angezeigt werden.

    Fügen Sie am Ende der CompatibilityLevelZeile Folgendes hinzu:
    COLLATE Latin1_General_CI_AS_KS_WS

    Führen Sie dann die Abfrage aus. Sicher genug, der Fehler besagt jetzt, dass es das AutoCloseFeld ist, das den Konflikt hat.

  2. Für unseren zweiten Test müssen wir die gerade vorgenommene Änderung rückgängig machen (dh die COLLATEKlausel vom Zeilenende entfernen) CompatibilityLevel.

    Wenn SQL Server nun wirklich in der Reihenfolge auswertet, in der die Felder angegeben sind, sollten wir in der Lage sein, Feld 1 (RecoveryModel) zu entfernen, wodurch das aktuelle Feld 2 (CompatibilityLevel) das Feld ist, für das die Master-Sortierung festgelegt wird das resultierende UNPIVOT. Und das CompatibilityLevelFeld ist ein Standardwert, der die Datenbanksortierung übernimmt. Der erste Fehler sollte daher das PageVerifyFeld sein, das eine Feldreferenz ist. Dies ist eine implizite Sortierung, die die ursprüngliche Sortierung beibehält, die in diesem Fall die ist Latin1_General_CI_AS_KS_WSund die nicht die ist Sortierung der aktuellen DB.

    So gehen Sie vor und kommentieren Sie die Zeile mit dem Start , RecoveryModelin dem SELECT(nach oben) und dann den Kommentar aus RecoveryModelder Zeile UNPIVOTKlausel unten und entfernen , um das führende Komma aus der folgenden Zeile , CompatibilityLevelso dass Sie keine Syntaxfehler erhalten.

    Führen Sie diese Abfrage aus. Sicher genug, der Fehler besagt jetzt, dass es das PageVerifyFeld ist, das den Konflikt hat.

  3. Für unseren dritten Test müssen wir die Änderungen rückgängig machen, die wir gerade vorgenommen haben, um das RecoveryModelFeld zu entfernen . Setzen Sie also das Komma zurück und kommentieren Sie die beiden anderen Zeilen aus.

    Jetzt können wir die andere Richtung einschlagen, indem wir eine Kollatierung erzwingen. Anstatt die Kollatierung der Coercible-Default-Kollatierungsfelder (die meisten davon) zu ändern, sollten wir die impliziten Kollatierungsfelder in die der aktuellen DB ändern können, oder?

    Ähnlich wie bei unserem ersten Test sollten wir in der Lage sein, die Sortierung von Feld 1 (RecoveryModel) mit einer expliziten COLLATEKlausel zu erzwingen . Wenn wir jedoch eine bestimmte Kollatierung angeben und dann die Abfrage in einer Datenbank mit einer anderen Kollatierung ausführen, wird die neue Kollatierung in den Feldern für die Standardkollatierung übernommen, die dann in Konflikt mit dem stehen, auf das wir dieses erste Feld einstellen. Das scheint ein Schmerz zu sein. Glücklicherweise gibt es eine dynamische Möglichkeit, damit umzugehen. Es gibt eine sogenannte Pseudo-Kollatierung DATABASE_DEFAULT, die die aktuelle Datenbank-Kollatierung aufnimmt (genau wie es die Coercible-Default-Felder tun).

    Gehen Sie vor und fügen Sie Folgendes am Ende der Zeile nach oben hinzu, beginnend mit , RecoveryModel: COLLATE DATABASE_DEFAULT

    Führen Sie diese Abfrage aus. Sicher genug, der Fehler besagt erneut, dass es das PageVerifyFeld ist, das den Konflikt hat.

  4. Für den letzten Test müssen wir keine der vorherigen Änderungen rückgängig machen.

    Alles, was wir jetzt tun müssen, um diese UNPIVOTAbfrage zu korrigieren, ist, das COLLATE DATABASE_DEFAULTam Ende der verbleibenden impliziten Kollatierungsfelder hinzuzufügen : PageVerifyund RestrictedAccess. Während das CollationFeld auch eine implizite Sortierung ist, stammt dieses Feld aus der masterDatenbank, die normalerweise mit der "aktuellen" Datenbank übereinstimmt. Wenn Sie jedoch auf Nummer sicher gehen möchten, damit dies immer funktioniert, fügen Sie das COLLATE DATABASE_DEFAULTam Ende dieses Felds hinzu.

    Führen Sie diese Abfrage aus. Klar genug, keine Fehler. Um diese Abfrage zu korrigieren COLLATE DATABASE_DEFAULT, musste nur das Ende von 3 Feldern (erforderlich) und möglicherweise eines weiteren (optional) hinzugefügt werden .

  5. Optional Test: Nachdem wir nun die UNPIVOT Abfrage schließlich haben ordnungsgemäß funktioniert, ändert nur eine von einem der Felddefinitionen mit Beginn CONVERT(VARCHAR(50),stattdessen sein 51, wie in: CONVERT(VARCHAR(51),.

    Führen Sie die Abfrage aus. Sie sollten den gleichen The type of column "X" conflicts with the type of other columns specified in the UNPIVOT list.Fehler erhalten, den Sie erhalten, wenn nur die Sortierung nicht übereinstimmt.

    Es ist nicht spezifisch genug, den gleichen Fehler für Datentyp- und Kollatierungsinkongruenzen zu erhalten, um wirklich hilfreich zu sein. Da gibt es also definitiv Verbesserungspotential :).


Anmerkung, die sich eher auf die Abfrage als auf die spezifische Frage zur Sortierung bezieht:

Da alle Quellfelder vom Datentyp sind NVARCHAR, wäre es für CONVERTalle Ausgabefelder sicherer , NVARCHARstatt VARCHAR. Möglicherweise haben Sie es im Moment nicht mit Daten zu tun, die Nicht-Standard-ASCII-Zeichen enthalten, aber die System-Metadaten ermöglichen es ihnen, NVARCHAR(128)mindestens in - das ist die größte maximale Länge aller dieser Felder - zu konvertieren garantiert, dass es in Zukunft kein Problem für Sie gibt oder für alle anderen, die diesen Code kopieren und möglicherweise bereits einige dieser Zeichen in ihrem System haben.


5

Dies ist eine Problemumgehung für das jeweilige Problem und keine vollständige Antwort auf die Frage. Sie können durch die Umstellung auf den Fehler vermeiden , sql_variantstatt 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;

Ich habe drei Spalten hinzugefügt, um Informationen zum zugrunde liegenden Typ der OptionValueSpalte zu erhalten.

Beispielausgabe

Wenn der Client keine sql_variantDaten verarbeiten kann, führen Sie eine endgültige Konvertierung (oberste Ebene) für die unpvt.OptionValueSpalte durch, z nvarchar(256).


4

Ok, also habe ich mir das angeschaut

sp_helptext [sys.databases]

dann brach zusammen, wo die Säulen herkamen. Die mit der Latin1_General_CI_AS_KS_WSSortierung stammen alle aus der Systemtabelle, bei sys.syspalvaluesder es sich anscheinend um eine generische Nachschlagetabelle handelt (es handelt sich um eine Systemtabelle, daher müssen Sie eine Verbindung über den DAC herstellen, um sie anzuzeigen.).

Ich vermute, dass es so eingestellt ist, dass es Latin1_General_CI_AS_KS_WSalle möglichen Nachschlagewerte verarbeitet. Ich kann sehen, wie nervig es wäre.

Eine andere Möglichkeit, die Definition (ursprünglich von Max in einem Kommentar bereitgestellt ) anzuzeigen, ist:

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';`
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.