Z dokumentów :
Ustawia pewne zachowania bazy danych, aby były zgodne z określoną wersją programu SQL Server.
...
Poziom zgodności zapewnia tylko częściową zgodność wsteczną z wcześniejszymi wersjami SQL Server. Użyj poziomu zgodności jako tymczasowej pomocy w migracji, aby obejść różnice między wersjami w zachowaniach kontrolowanych przez odpowiednie ustawienie poziomu zgodności.
W mojej interpretacji tryb zgodności dotyczy zachowania i analizowania składni, a nie takich rzeczy jak parser mówiący: „Hej, nie możesz użyć ROW_NUMBER()
!” Czasami niższy poziom zgodności pozwala na dalsze unikanie składni, która nie jest już obsługiwana, a czasami uniemożliwia korzystanie z nowych konstrukcji składni. Dokumentacja zawiera kilka wyraźnych przykładów, ale oto kilka demonstracji:
Przekazywanie wbudowanych funkcji jako argumentów funkcji
Ten kod działa na poziomie zgodności 90+:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);
Ale w 80 daje:
Msg 102, poziom 15, stan 1
Niepoprawna składnia w pobliżu „(”.
Szczególny problem polega na tym, że w 80 nie można przekazać funkcji wbudowanej w funkcję. Jeśli chcesz pozostać w trybie zgodności 80, możesz obejść ten problem, mówiąc:
DECLARE @db_id INT = DB_ID();
SELECT *
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);
Przekazywanie typu tabeli do funkcji o wartości tabeli
Podobnie do powyższego, możesz otrzymać błąd składniowy podczas używania TVP i próby przekazania go do funkcji o wartości tabeli. Działa to na współczesnych poziomach kompatybilności:
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);
Zmień jednak poziom zgodności na 80 i ponownie uruchom trzy ostatnie linie; pojawia się ten komunikat o błędzie:
Msg 137, poziom 16, stan 1, wiersz 19
Musi zadeklarować zmienną skalarną „@foo”.
Naprawdę nie ma dobrego obejścia poza szczytem mojej głowy, poza podniesieniem poziomu zgodności lub uzyskaniem wyników w inny sposób.
Używanie kwalifikowanych nazw kolumn w ZASTOSUJ
W trybie zgodności 90 i nowszym możesz to zrobić bez problemu:
SELECT * FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;
Jednak w trybie zgodności 80 kolumna kwalifikowana przekazana do funkcji wywołuje ogólny błąd składniowy:
Msg 102, poziom 15, stan 1
Niepoprawna składnia w pobliżu „.”.
ORDER BY alias, który pasuje do nazwy kolumny
Rozważ to zapytanie:
SELECT name = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.name;
W trybie zgodności 80 wyniki są następujące:
001_ofni_epytatad_ps sp_datatype_info_100
001_scitsitats_ps sp_statistics_100
001_snmuloc_corps_ps sp_sproc_columns_100
...
W trybie zgodności 90 wyniki są zupełnie inne:
snmuloc_lla all_columns
stcejbo_lla all_objects
sretemarap_lla all_parameters
...
Powód? W trybie zgodności 80 prefiks tabeli jest całkowicie ignorowany, więc jest uporządkowany według wyrażenia zdefiniowanego przez alias na SELECT
liście. W nowszych poziomach zgodności brany jest pod uwagę prefiks tabeli, więc SQL Server faktycznie użyje tej kolumny w tabeli (jeśli zostanie znaleziona). Jeśli ORDER BY
w tabeli nie znaleziono aliasu, nowsze poziomy zgodności nie wybaczają tak bardzo dwuznaczności. Rozważ ten przykład:
SELECT myname = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.myname;
Wynik jest uporządkowany według myname
wyrażenia w 80, ponieważ ponownie prefiks tabeli jest ignorowany, ale w 90 generuje ten komunikat o błędzie:
Msg 207, poziom 16, stan 1, wiersz 3
Niepoprawna nazwa kolumny „moja nazwa”.
Wszystko to wyjaśniono również w dokumentacji :
Podczas wiązania odniesień ORDER BY
do kolumn na liście z kolumnami zdefiniowanymi na SELECT
liście, niejednoznaczności kolumn są ignorowane, a prefiksy kolumn są czasami ignorowane. Może to spowodować, że zestaw wyników zwróci się w nieoczekiwanej kolejności.
Na przykład ORDER BY
klauzula z pojedynczą dwuczęściową kolumną ( <table_alias>.<column>
), która jest używana jako odwołanie do kolumny na liście SELECT, jest akceptowana, ale alias tabeli jest ignorowany. Rozważ następujące zapytanie.
SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1
Po uruchomieniu prefiks kolumny jest ignorowany w pliku ORDER BY
. Operacja sortowania nie występuje x.c1
zgodnie z oczekiwaniami na określonej kolumnie źródłowej ( ); zamiast tego występuje na pochodnejc1
kolumna zdefiniowana w zapytaniu. Plan wykonania dla tego zapytania pokazuje, że wartości dla kolumny pochodnej są najpierw obliczane, a następnie wartości obliczane są sortowane.
ZAMÓW PRZEZ coś, czego nie ma na liście WYBIERZ
W trybie zgodności 90 nie można tego zrobić:
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;
Wynik:
Msg 104, poziom 16, stan 1
ORDER BY elementy muszą pojawić się na liście wyboru, jeśli instrukcja zawiera operator UNION, INTERSECT lub EXCEPT.
Jednak w 80 można nadal używać tej składni.
Stare, obskurne połączenia zewnętrzne
Tryb 80 pozwala również na użycie starej, przestarzałej składni sprzężenia zewnętrznego ( *=/=*
):
SELECT o.name, c.name
FROM sys.objects AS o, sys.columns AS c
WHERE o.[object_id] *= c.[object_id];
W SQL Server 2008/2008 R2, jeśli masz 90 lat lub więcej, pojawia się następujący komunikat:
Msg 4147, poziom 15, stan 1
W zapytaniu zastosowano zewnętrzne operatory łączenia inne niż ANSI („ *=
” lub „ =*
”). Aby uruchomić to zapytanie bez modyfikacji, ustaw poziom zgodności dla bieżącej bazy danych na 80, używając opcji SET COMPATIBILITY_LEVEL opcji ALTER DATABASE. Zdecydowanie zaleca się przepisanie zapytania przy użyciu zewnętrznych operatorów złącz ANSI (POŁĄCZENIE ZEWNĘTRZNE, POŁĄCZENIE ZEWNĘTRZNE). W przyszłych wersjach SQL Server operatory łączenia inne niż ANSI nie będą obsługiwane nawet w trybach zgodności wstecznej.
W SQL Server 2012 w ogóle nie jest to już poprawna składnia i powoduje:
Msg 102, poziom 15, stan 1, wiersz 3
Niepoprawna składnia w pobliżu „* =”.
Oczywiście w SQL Server 2012 nie można już obejść tego problemu przy użyciu poziomu zgodności, ponieważ 80 nie jest już obsługiwany. Jeśli uaktualnisz bazę danych w trybie zgodności z 80 (poprzez uaktualnienie na miejscu, odłączenie / dołączenie, tworzenie kopii zapasowych / przywracanie, wysyłanie dziennika, tworzenie kopii lustrzanych itp.), Zostanie ona automatycznie uaktualniona do 90.
Wskazówki do tabeli bez Z
W trybie kompatybilności z 80 można użyć następujących elementów i przestrzegać podpowiedzi dotyczących tabeli:
SELECT * FROM dbo.whatever NOLOCK;
W 90+ NOLOCK
nie jest to już wskazówka przy stole, to jest alias. W przeciwnym razie zadziałałoby to:
SELECT * FROM dbo.whatever AS w NOLOCK;
Ale to nie:
Msg 1018, poziom 15, stan 1
Niepoprawna składnia w pobliżu „NOLOCK”. Jeśli jest to zamierzone jako podpowiedź do tabeli, słowo kluczowe A WITH i nawiasy są teraz wymagane. Zobacz SQL Server Books Online, aby uzyskać odpowiednią składnię.
Teraz, aby udowodnić, że zachowanie nie jest obserwowane w pierwszym przykładzie w trybie zgodności z 90, użyj AdventureWorks (upewniając się, że jest na wyższym poziomie kompatybilności) i uruchom następujące polecenie:
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;
Jest to szczególnie problematyczne, ponieważ zachowanie zmienia się bez komunikatu o błędzie lub nawet błędu. Jest to również coś, czego doradca uaktualnienia i inne narzędzia mogą nawet nie zauważyć, ponieważ jest to alias tabeli.
Konwersje obejmujące nowe typy daty / godziny
Nowe typy daty / godziny wprowadzone w SQL Server 2008 (np. date
I datetime2
) obsługują znacznie większy zakres niż oryginalny datetime
i smalldatetime
). Jawne konwersje wartości poza obsługiwanym zakresem zakończą się niepowodzeniem bez względu na poziom zgodności, na przykład:
SELECT CONVERT(SMALLDATETIME, '00010101');
Wydajność:
Msg 242, poziom 16, stan 3
Konwersja typu danych varchar na typ danych smalldatetime spowodowała powstanie wartości spoza zakresu.
Jednak niejawne konwersje sprawdzą się na nowszych poziomach zgodności. Na przykład będzie to działać w 100+:
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
Ale w 80 (a także w 90) daje podobny błąd jak powyżej:
Msg 242, poziom 16, stan 3
Konwersja typu danych varchar na typ danych data-godzina spowodowała, że wartość była poza zakresem.
Nadmiarowe klauzule FOR w wyzwalaczach
To jest niejasny scenariusz, który pojawił się tutaj . W trybie zgodności 80 zakończy się to powodzeniem:
CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;
W wersji 90 i wyższej nie jest to już analizowane, a zamiast tego pojawia się następujący komunikat o błędzie:
Msg 1034, poziom 15, stan 1, procedura tx
Błąd składniowy: zduplikowana specyfikacja akcji „UPDATE” w deklaracji wyzwalacza.
PIVOT / UNPIVOT
Niektóre formy składni nie działają poniżej 80 (ale działają dobrze w 90+):
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
Daje to:
Msg 156, poziom 15, stan 1
Niepoprawna składnia w pobliżu słowa kluczowego „for”.
Aby CROSS APPLY
zapoznać się z niektórymi obejściami, w tym zobacz te odpowiedzi .
Nowe wbudowane funkcje
Spróbuj użyć nowych funkcji, takich jak TRY_CONVERT()
w bazie danych o poziomie zgodności <110. Po prostu w ogóle ich nie rozpoznaje.
SELECT TRY_CONVERT(INT, 1);
Wynik:
Msg 195, poziom 15, stan 10
„TRY_CONVERT” nie jest rozpoznaną nazwą wbudowanej funkcji.
Zalecenie
Używaj trybu zgodności 80 tylko wtedy, gdy go potrzebujesz. Ponieważ nie będzie już dostępny w następnej wersji po 2008 R2, ostatnią rzeczą, którą chcesz zrobić, to napisać kod na tym poziomie kompatybilności, polegać na zachowaniach, które widzisz, a następnie mieć cały szereg zepsucia, gdy nie możesz już użyj tego poziomu zgodności. Myśl dalej i nie próbuj zamalować się w kącie, kupując czas na kontynuowanie starej, przestarzałej składni.