Aus den Dokumenten :
Legt fest, dass bestimmte Datenbankverhalten mit der angegebenen Version von SQL Server kompatibel sind.
... Die
Kompatibilitätsstufe bietet nur teilweise Abwärtskompatibilität mit früheren Versionen von SQL Server. Verwenden Sie die Kompatibilitätsstufe als vorläufige Migrationshilfe, um Versionsunterschiede in den Verhaltensweisen zu umgehen, die von der jeweiligen Einstellung der Kompatibilitätsstufe gesteuert werden.
In meiner Interpretation geht es im Kompatibilitätsmodus um das Verhalten und Parsen der Syntax, nicht für Dinge wie den Parser, die sagen: "Hey, du kannst nicht verwenden ROW_NUMBER()
!" Manchmal können Sie mit der niedrigeren Kompatibilitätsstufe fortfahren, wenn die Syntax nicht mehr unterstützt wird, und manchmal können Sie keine neuen Syntaxkonstrukte mehr verwenden. In der Dokumentation werden einige explizite Beispiele aufgeführt, aber hier sind einige Demonstrationen:
Eingebaute Funktionen als Funktionsargumente übergeben
Dieser Code funktioniert in Kompatibilitätsstufe 90+:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);
Aber in 80 ergibt es:
Meldung 102, Ebene 15, Status 1
Falsche Syntax in der Nähe von '('.
Das spezielle Problem hierbei ist, dass Sie in 80 keine integrierte Funktion an eine Funktion übergeben dürfen. Wenn Sie im Kompatibilitätsmodus 80 bleiben möchten, können Sie dies umgehen, indem Sie sagen:
DECLARE @db_id INT = DB_ID();
SELECT *
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);
Übergeben eines Tabellentyps an eine Tabellenwertfunktion
Ähnlich wie oben können Sie einen Syntaxfehler erhalten, wenn Sie einen TVP verwenden und versuchen, ihn an eine Tabellenwertfunktion zu übergeben. Dies funktioniert in modernen Kompatibilitätsstufen:
CREATE TYPE dbo.foo AS TABLE(bar INT);
GO
CREATE FUNCTION dbo.whatever
(
@foo dbo.foo READONLY
)
RETURNS TABLE
AS
RETURN (SELECT bar FROM @foo);
GO
DECLARE @foo dbo.foo;
INSERT @foo(bar) SELECT 1;
SELECT * FROM dbo.whatever(@foo);
Ändern Sie jedoch die Kompatibilitätsstufe auf 80 und führen Sie die letzten drei Zeilen erneut aus. Sie erhalten diese Fehlermeldung:
Meldung 137, Ebene 16,
Status 1, Zeile 19
Die skalare Variable "@foo" muss deklariert werden.
Keine wirklich gute Lösung, außer die Kompatibilitätsstufe zu verbessern oder die Ergebnisse auf eine andere Art und Weise zu erhalten.
Verwenden qualifizierter Spaltennamen in APPLY
Im Kompatibilitätsmodus 90 und höher können Sie dies problemlos tun:
SELECT * FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;
Im Kompatibilitätsmodus 80 führt die an die Funktion übergebene qualifizierte Spalte jedoch zu einem generischen Syntaxfehler:
Meldung 102, Ebene 15, Status 1
Falsche Syntax in der Nähe von '.'.
ORDER BY ein Alias, der einem Spaltennamen entspricht
Betrachten Sie diese Abfrage:
SELECT name = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.name;
Im 80-Kompatibilitätsmodus lauten die Ergebnisse wie folgt:
001_ofni_epytatad_ps sp_datatype_info_100
001_scitsitats_ps sp_statistics_100
001_snmuloc_corps_ps sp_sproc_columns_100
...
Im 90-Kompatibilitätsmodus sind die Ergebnisse sehr unterschiedlich:
snmuloc_lla all_columns
stcejbo_lla all_objects
sretemarap_lla all_parameters
...
Der Grund? Im Kompatibilitätsmodus 80 wird das Tabellenpräfix vollständig ignoriert, sodass die Reihenfolge nach dem durch den Alias in der SELECT
Liste definierten Ausdruck erfolgt . In neueren Kompatibilitätsstufen wird das Tabellenpräfix berücksichtigt, sodass SQL Server diese Spalte in der Tabelle tatsächlich verwendet (sofern sie gefunden wird). Wenn der ORDER BY
Alias nicht in der Tabelle gefunden wird, verzeihen die neueren Kompatibilitätsstufen keine Mehrdeutigkeit. Betrachten Sie dieses Beispiel:
SELECT myname = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.myname;
Das Ergebnis wird nach dem myname
Ausdruck in 80 geordnet , da das Tabellenpräfix erneut ignoriert wird, in 90 jedoch die folgende Fehlermeldung generiert wird:
Meldung 207, Ebene 16,
Status 1, Zeile 3
Ungültiger Spaltenname 'Mein Name'.
Dies alles wird auch in der Dokumentation erklärt :
Wenn Sie die Spaltenverweise in der ORDER BY
Liste an die in der SELECT
Liste definierten Spalten binden , werden Spaltenmehrdeutigkeiten ignoriert und Spaltenpräfixe manchmal ignoriert. Dies kann dazu führen, dass die Ergebnismenge in einer unerwarteten Reihenfolge zurückgegeben wird.
Eine ORDER BY
Klausel mit einer einzelnen zweiteiligen column ( <table_alias>.<column>
), die als Verweis auf eine Spalte in einer SELECT-Liste verwendet wird, wird beispielsweise akzeptiert, der Tabellenalias wird jedoch ignoriert. Betrachten Sie die folgende Abfrage.
SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1
Bei der Ausführung wird das Spaltenpräfix in der ignoriert ORDER BY
. Der Sortiervorgang wird nicht x.c1
wie erwartet für die angegebene Quellenspalte ( ) ausgeführt. stattdessen tritt es auf der abgeleitetenc1
Spalte, die in der Abfrage definiert ist. Der Ausführungsplan für diese Abfrage zeigt, dass zuerst die Werte für die abgeleitete Spalte berechnet und dann die berechneten Werte sortiert werden.
ORDER BY etwas nicht in der SELECT-Liste
Im 90-Kompatibilitätsmodus können Sie dies nicht tun:
SELECT name = COALESCE(a.name, '') FROM sys.objects AS a
UNION ALL
SELECT name = COALESCE(a.name, '') FROM sys.objects AS a
ORDER BY a.name;
Ergebnis:
Nachricht 104, Ebene 16
, Status 1
ORDER BY-Elemente müssen in der Auswahlliste angezeigt werden, wenn die Anweisung einen UNION-, INTERSECT- oder EXCEPT-Operator enthält.
In 80 können Sie diese Syntax jedoch weiterhin verwenden.
Alte, eklige äußere Fugen
Im 80-Modus können Sie auch die alte, veraltete Outer-Join-Syntax ( *=/=*
) verwenden:
SELECT o.name, c.name
FROM sys.objects AS o, sys.columns AS c
WHERE o.[object_id] *= c.[object_id];
Wenn Sie in SQL Server 2008/2008 R2 mindestens 90 Jahre alt sind, erhalten Sie die folgende ausführliche Meldung:
Meldung 4147, Ebene 15, Status 1
Die Abfrage verwendet Nicht-ANSI-Outer-Join-Operatoren (" *=
" oder " =*
"). Um diese Abfrage ohne Änderung auszuführen, legen Sie die Kompatibilitätsstufe für die aktuelle Datenbank mit der Option SET COMPATIBILITY_LEVEL von ALTER DATABASE auf 80 fest. Es wird dringend empfohlen, die Abfrage mit ANSI-Outer-Join-Operatoren (LEFT OUTER JOIN, RIGHT OUTER JOIN) neu zu schreiben. In zukünftigen Versionen von SQL Server werden Nicht-ANSI-Verknüpfungsoperatoren auch in Abwärtskompatibilitätsmodi nicht unterstützt.
In SQL Server 2012 ist diese Syntax nicht mehr gültig und führt zu folgenden Ergebnissen:
Meldung 102, Ebene 15, Status 1, Zeile 3
Falsche Syntax in der Nähe von '* ='.
In SQL Server 2012 können Sie dieses Problem natürlich nicht mehr mithilfe der Kompatibilitätsstufe umgehen, da 80 nicht mehr unterstützt wird. Wenn Sie eine Datenbank im 80-Kompatibilitätsmodus aktualisieren (durch direktes Upgrade, Trennen / Anhängen, Sichern / Wiederherstellen, Protokollversand, Spiegeln usw.), wird diese automatisch auf 90 für Sie aktualisiert.
Tabellenhinweise ohne WITH
Im Kompatibilitätsmodus 80 können Sie Folgendes verwenden, und der Tabellenhinweis wird beachtet:
SELECT * FROM dbo.whatever NOLOCK;
Ab 90 NOLOCK
ist das kein Tabellenhinweis mehr, sondern ein Alias. Andernfalls würde dies funktionieren:
SELECT * FROM dbo.whatever AS w NOLOCK;
Aber das tut es nicht:
Meldung 1018, Ebene 15,
Status 1
Falsche Syntax in der Nähe von 'NOLOCK'. Wenn dies als Teil eines Tabellenhinweises gedacht ist, sind jetzt ein WITH-Schlüsselwort und eine Klammer erforderlich. Informationen zur richtigen Syntax finden Sie in der SQL Server-Onlinedokumentation.
Um zu beweisen, dass das Verhalten im ersten Beispiel im 90-Kompatibilitätsmodus nicht beobachtet wird, verwenden Sie AdventureWorks (stellen Sie sicher, dass es sich auf einer höheren Kompatibilitätsstufe befindet) und führen Sie Folgendes aus:
BEGIN TRANSACTION;
SELECT TOP (1) * FROM Sales.SalesOrderHeader UPDLOCK;
SELECT * FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
AND resource_type IN ('KEY', 'OBJECT'); -- how many rows here? 0
COMMIT TRANSACTION;
BEGIN TRANSACTION;
SELECT TOP (1) * FROM Sales.SalesOrderHeader WITH (UPDLOCK);
SELECT * FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
AND resource_type IN ('KEY', 'OBJECT'); -- how many rows here? 2
COMMIT TRANSACTION;
Dies ist besonders problematisch, da sich das Verhalten ohne eine Fehlermeldung oder sogar einen Fehler ändert. Und es ist auch etwas, das der Upgrade-Berater und andere Tools möglicherweise nicht einmal erkennen, da es sich, soweit bekannt, um einen Tabellenalias handelt.
Konvertierungen mit neuen Datums- / Zeittypen
Die in SQL Server 2008 eingeführten neuen Datums- / Uhrzeit-Typen (z. B. date
und datetime2
) unterstützen einen viel größeren Bereich als das ursprüngliche datetime
und smalldatetime
. Explizite Konvertierungen von Werten außerhalb des unterstützten Bereichs schlagen fehl, unabhängig von der Kompatibilitätsstufe. Beispiel:
SELECT CONVERT(SMALLDATETIME, '00010101');
Erträge:
Meldung 242, Ebene 16,
Status 3 Die Konvertierung eines varchar-Datentyps in einen smalldatetime-Datentyp führte zu einem Wert außerhalb des Bereichs.
Implizite Konvertierungen funktionieren jedoch in den neueren Kompatibilitätsstufen. Zum Beispiel wird dies in 100+ funktionieren:
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
Aber in 80 (und auch in 90) ergibt sich ein ähnlicher Fehler wie oben:
Meldung 242, Ebene 16,
Status 3 Die Konvertierung eines varchar-Datentyps in einen datetime-Datentyp führte zu einem Wert außerhalb des zulässigen Bereichs.
Redundante FOR-Klauseln in Triggern
Dies ist ein obskures Szenario, das hier aufgetaucht ist . Im Kompatibilitätsmodus 80 ist dies erfolgreich:
CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;
Bei Kompatibilität mit 90 und höher wird dies nicht mehr analysiert, und stattdessen wird die folgende Fehlermeldung angezeigt:
Meldung 1034, Ebene 15, Status 1, Prozedur tx
Syntaxfehler: Doppelte Angabe der Aktion "UPDATE" in der Triggerdeklaration.
PIVOT / UNPIVOT
Einige Syntaxformen funktionieren nicht unter 80 (aber gut in 90+):
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
Dies ergibt:
Meldung 156, Ebene 15, Status 1
Falsche Syntax neben dem Schlüsselwort 'for'.
Für einige Abhilfen, einschließlich CROSS APPLY
finden diese Antworten .
Neue eingebaute Funktionen
Versuchen Sie, neue Funktionen wie TRY_CONVERT()
in einer Datenbank mit einem Kompatibilitätsgrad <110 zu verwenden. Sie werden dort einfach überhaupt nicht erkannt.
SELECT TRY_CONVERT(INT, 1);
Ergebnis:
Meldung 195, Ebene 15,
Status 10
'TRY_CONVERT' ist kein erkannter Name für die integrierte Funktion.
Empfehlung
Verwenden Sie den Kompatibilitätsmodus 80 nur, wenn Sie ihn tatsächlich benötigen. Da es in der nächsten Version nach 2008 R2 nicht mehr verfügbar ist, müssen Sie als Letztes Code in dieser Kompatibilitätsstufe schreiben, sich auf das Verhalten verlassen, das Sie sehen, und dann eine ganze Reihe von Fehlern haben, wenn Sie dies nicht mehr können benutze diesen kompatiblen Level. Denken Sie vorausschauend und versuchen Sie nicht, sich selbst in eine Ecke zu malen, indem Sie sich Zeit nehmen, um weiterhin alte, veraltete Syntax zu verwenden.