Dari dokumen :
Menetapkan perilaku basis data tertentu agar kompatibel dengan versi SQL Server yang ditentukan.
...
Tingkat kompatibilitas hanya menyediakan kompatibilitas sebagian dengan versi SQL Server sebelumnya. Gunakan tingkat kompatibilitas sebagai bantuan migrasi sementara untuk mengatasi perbedaan versi dalam perilaku yang dikendalikan oleh pengaturan tingkat kompatibilitas yang relevan.
Dalam interpretasi saya, mode kompatibilitas adalah tentang perilaku dan penguraian sintaks, bukan untuk hal-hal seperti pengurai yang mengatakan, "Hei, Anda tidak dapat menggunakan ROW_NUMBER()
!" Kadang-kadang tingkat kompatibilitas yang lebih rendah memungkinkan Anda untuk terus pergi dengan sintaks yang tidak lagi didukung, dan kadang-kadang mencegah Anda menggunakan konstruksi sintaksis baru. Dokumentasi berisi beberapa contoh eksplisit, tetapi berikut adalah beberapa demonstrasi:
Melewati fungsi bawaan sebagai argumen fungsi
Kode ini berfungsi di tingkat kompatibilitas 90+:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);
Tapi di 80 itu menghasilkan:
Msg 102, Level 15, Negara 1
Sintaksis salah dekat '('.
Masalah khusus di sini adalah bahwa di 80 Anda tidak diizinkan untuk melewatkan fungsi bawaan ke fungsi. Jika Anda ingin tetap dalam 80 mode kompatibilitas, Anda dapat mengatasi ini dengan mengatakan:
DECLARE @db_id INT = DB_ID();
SELECT *
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);
Mengirimkan tipe tabel ke fungsi bernilai tabel
Mirip dengan di atas, Anda bisa mendapatkan kesalahan sintaksis saat menggunakan TVP dan mencoba meneruskannya ke fungsi bernilai tabel. Ini berfungsi di level compat modern:
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);
Namun, ubah tingkat kompatibilitas menjadi 80, dan jalankan tiga baris terakhir lagi; Anda mendapatkan pesan kesalahan ini:
Msg 137, Level 16, State 1, Line 19
Harus mendeklarasikan variabel skalar "@foo".
Tidak benar-benar ada solusi yang baik dari atas kepala saya, selain meningkatkan level compat atau mendapatkan hasil dengan cara yang berbeda.
Menggunakan nama kolom yang memenuhi syarat dalam BERLAKU
Dalam 90 mode kompatibilitas dan ke atas, Anda dapat melakukan ini tanpa masalah:
SELECT * FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;
Namun, dalam 80 mode kompatibilitas, kolom yang memenuhi syarat diserahkan ke fungsi menimbulkan kesalahan sintaksis umum:
Msg 102, Level 15, Negara 1
Sintaks salah dekat '.'
ORDER OLEH alias yang kebetulan cocok dengan nama kolom
Pertimbangkan pertanyaan ini:
SELECT name = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.name;
Dalam 80 mode kompatibilitas, hasilnya adalah sebagai berikut:
001_ofni_epytatad_ps sp_datatype_info_100
001_scitsitats_ps sp_statistics_100
001_snmuloc_corps_ps sp_sproc_columns_100
...
Dalam 90 mode kompatibilitas, hasilnya sangat berbeda:
snmuloc_lla all_columns
stcejbo_lla all_objects
sretemarap_lla all_parameters
...
Alasannya? Dalam 80 mode kompatibilitas, awalan tabel diabaikan seluruhnya, sehingga memesan dengan ekspresi yang ditentukan oleh alias dalam SELECT
daftar. Di tingkat kompatibilitas yang lebih baru, awalan tabel dipertimbangkan, jadi SQL Server akan benar-benar menggunakan kolom itu dalam tabel (jika ditemukan). Jika ORDER BY
alias tidak ditemukan dalam tabel, tingkat kompatibilitas yang lebih baru tidak begitu memaafkan tentang ambiguitas. Pertimbangkan contoh ini:
SELECT myname = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.myname;
Hasilnya dipesan oleh myname
ekspresi dalam 80, karena sekali lagi awalan tabel diabaikan, tetapi di 90 itu menghasilkan pesan kesalahan ini:
Msg 207, Level 16, Negara 1, Baris 3
Nama kolom 'myname' tidak valid.
Ini semua dijelaskan juga dalam dokumentasi :
Saat mengikat referensi kolom dalam ORDER BY
daftar ke kolom yang ditentukan dalam SELECT
daftar, ambiguitas kolom diabaikan dan awalan kolom terkadang diabaikan. Ini dapat menyebabkan hasil diatur untuk kembali dalam urutan yang tidak terduga.
Misalnya, ORDER BY
klausa dengan satu kolom dua bagian ( <table_alias>.<column>
) yang digunakan sebagai referensi ke kolom dalam daftar SELECT diterima, tetapi tabel alias diabaikan. Pertimbangkan pertanyaan berikut.
SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1
Ketika dieksekusi, awalan kolom diabaikan dalam ORDER BY
. Operasi penyortiran tidak terjadi pada kolom sumber yang ditentukan ( x.c1
) seperti yang diharapkan; alih-alih itu terjadi pada turunanc1
kolom yang didefinisikan dalam kueri. Rencana eksekusi untuk kueri ini menunjukkan bahwa nilai-nilai untuk kolom yang diturunkan dihitung pertama dan kemudian nilai yang dihitung diurutkan.
ORDER BY sesuatu yang tidak ada dalam daftar SELECT
Dalam 90 mode kompatibilitas, Anda tidak dapat melakukan ini:
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;
Hasil:
Msg 104, Level 16, Negara 1
ORDER BY item harus muncul dalam daftar pilih jika pernyataan berisi operator UNION, INTERSECT atau KECUALI.
Namun, dalam 80, Anda masih bisa menggunakan sintaks ini.
Tua, luar bergabung dengan icky
Mode 80 juga memungkinkan Anda untuk menggunakan sintaks gabungan luar yang lama dan usang ( *=/=*
):
SELECT o.name, c.name
FROM sys.objects AS o, sys.columns AS c
WHERE o.[object_id] *= c.[object_id];
Di SQL Server 2008/2008 R2, jika Anda berada di 90 atau lebih besar, Anda mendapatkan pesan verbose ini:
Msg 4147, Level 15, Negara 1
Permintaan menggunakan operator bergabung luar non-ANSI (" *=
" atau " =*
"). Untuk menjalankan kueri ini tanpa modifikasi, harap setel tingkat kompatibilitas untuk database saat ini ke 80, menggunakan opsi SET COMPATIBILITY_LEVEL dari ALTER DATABASE. Sangat disarankan untuk menulis ulang kueri menggunakan operator join luar ANSI (LEFT OUTER JOIN, RIGHT OUTER JOIN). Dalam versi SQL Server yang akan datang, operator gabungan non-ANSI tidak akan didukung bahkan dalam mode kompatibilitas-mundur.
Dalam SQL Server 2012, ini sama sekali tidak lagi sintaks yang valid, dan menghasilkan yang berikut:
Msg 102, Level 15, Negara 1, Baris 3
Sintaks salah dekat '* ='.
Tentu saja dalam SQL Server 2012 Anda tidak dapat lagi mengatasi masalah ini menggunakan tingkat kompatibilitas, karena 80 tidak lagi didukung. Jika Anda memutakhirkan basis data dalam mode compat 80 (dengan pemutakhiran di tempat, lepas / pasang, cadangan / kembalikan, pengiriman log, mirroring, dll.) Secara otomatis akan ditingkatkan menjadi 90 untuk Anda.
Petunjuk tabel tanpa DENGAN
Dalam mode 80 compat, Anda dapat menggunakan yang berikut dan petunjuk tabel akan diamati:
SELECT * FROM dbo.whatever NOLOCK;
Dalam 90+, itu NOLOCK
bukan lagi petunjuk tabel, ini adalah alias. Kalau tidak, ini akan berhasil:
SELECT * FROM dbo.whatever AS w NOLOCK;
Tetapi tidak:
Msg 1018, Level 15, Negara 1
Sintaksis salah dekat 'NOLOCK'. Jika ini dimaksudkan sebagai bagian dari petunjuk tabel, kata kunci WITH dan tanda kurung sekarang diperlukan. Lihat SQL Server Books Online untuk sintaksis yang tepat.
Sekarang, untuk membuktikan bahwa perilaku tidak diamati dalam contoh pertama ketika dalam mode 90 compat, gunakan AdventureWorks (pastikan itu dalam level compat yang lebih tinggi) dan jalankan yang berikut:
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;
Yang ini sangat bermasalah karena perilaku berubah tanpa pesan kesalahan atau bahkan kesalahan. Dan itu juga sesuatu yang bahkan tidak bisa dilihat oleh penasihat peningkatan dan alat-alat lain, karena untuk semua yang tahu, itu adalah tabel alias.
Konversi yang melibatkan jenis tanggal / waktu baru
Tipe tanggal / waktu baru yang diperkenalkan dalam SQL Server 2008 (misalnya date
dan datetime2
) mendukung rentang yang jauh lebih besar daripada yang asli datetime
dan smalldatetime
). Konversi nilai-nilai eksplisit di luar rentang yang didukung akan gagal apa pun tingkat kompatibilitasnya, misalnya:
SELECT CONVERT(SMALLDATETIME, '00010101');
Hasil:
Msg 242, Level 16, Negara 3
Konversi tipe data varchar ke tipe data waktu-kecil menghasilkan nilai di luar kisaran.
Namun, konversi tersirat akan bekerja sendiri di tingkat kompatibilitas yang lebih baru. Misalnya ini akan bekerja di 100+:
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
Namun di 80 (dan juga di 90), ia menghasilkan kesalahan yang sama seperti di atas:
Msg 242, Level 16, Negara 3
Konversi tipe data varchar ke tipe data datetime menghasilkan nilai di luar kisaran.
Klausa redundansi untuk pemicu
Ini adalah skenario yang tidak jelas yang muncul di sini . Dalam 80 mode kompatibilitas, ini akan berhasil:
CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;
Di 90 kompatibilitas dan lebih tinggi, ini tidak lagi diuraikan, dan sebagai gantinya Anda mendapatkan pesan kesalahan berikut:
Msg 1034, Level 15, Status 1, Prosedur tx
Kesalahan sintaks: Spesifikasi duplikat dari tindakan "UPDATE" dalam deklarasi pemicu.
PIVOT / UNPIVOT
Beberapa bentuk sintaks tidak akan berfungsi di bawah 80 (tetapi berfungsi dengan baik di 90+):
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
Ini menghasilkan:
Msg 156, Level 15, Negara 1
Sintaksis salah di dekat kata kunci 'untuk'.
Untuk beberapa solusi, termasuk CROSS APPLY
, lihat jawaban ini .
Fungsi bawaan baru
Coba gunakan fungsi baru seperti TRY_CONVERT()
dalam database dengan tingkat kompatibilitas <110. Mereka sama sekali tidak dikenali di sana.
SELECT TRY_CONVERT(INT, 1);
Hasil:
Msg 195, Level 15, Negara 10
'TRY_CONVERT' bukan nama fungsi bawaan yang dikenali.
Rekomendasi
Gunakan hanya 80 mode kompatibilitas jika Anda benar-benar membutuhkannya. Karena itu tidak akan lagi tersedia di versi berikutnya setelah 2008 R2, hal terakhir yang ingin Anda lakukan adalah menulis kode di level ini, bergantung pada perilaku yang Anda lihat, dan kemudian memiliki sejumlah kerusakan ketika Anda tidak bisa lagi gunakan level compat itu. Berpikir maju ke depan dan jangan mencoba melukis diri sendiri dengan membeli waktu untuk terus menggunakan sintaks yang sudah usang.