Gönderen docs :
Bazı veritabanı davranışlarını, belirtilen SQL Server sürümüyle uyumlu olacak şekilde ayarlar.
...
Uyumluluk seviyesi, SQL Server'ın önceki sürümleriyle yalnızca kısmen geriye dönük uyumluluk sağlar. İlgili uyumluluk düzeyi ayarıyla kontrol edilen davranışlardaki sürüm farklılıkları etrafında çalışmak için uyumluluk düzeyini geçici bir geçiş yardımcısı olarak kullanın.
Benim yorumumda, uyumluluk modu, "Ayrıştırıcı kullanamazsınız ROW_NUMBER()
!" Diyen şeyler için değil, sözdizimi davranış ve ayrıştırma hakkındadır . Bazen düşük uyumluluk seviyesi, artık desteklenmeyen sözdizimi ile kurtulmaya devam etmenize izin verir ve bazen yeni sözdizimi yapıları kullanmanızı önler. Belgeler birkaç açık örneği listeliyor, ancak işte birkaç örnek:
Yerleşik işlevleri işlev argümanları olarak geçirme
Bu kod 90+ uyumluluk düzeyinde çalışır:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);
Ancak 80 yılında verim:
Mesaj 102, Seviye 15, Durum 1
'(' yakınında yanlış sözdizimi.
Buradaki spesifik sorun, 80'de yerleşik bir işlevi bir işleve geçirmenize izin verilmemesidir. 80 uyumluluk modunda kalmak istiyorsanız, şunu söyleyerek bu sorunu çözebilirsiniz:
DECLARE @db_id INT = DB_ID();
SELECT *
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);
Tablo türündeki bir tablo türüne bir tablo türü iletme
Yukarıdakilere benzer şekilde, TVP kullanırken ve tablo değerli bir işleve aktarmaya çalışırken bir sözdizimi hatası alabilirsiniz. Bu, modern uyumluluk seviyelerinde çalışır:
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);
Ancak, uyumluluk düzeyini 80 olarak değiştirin ve son üç satırı tekrar çalıştırın; bu hata iletisini alıyorsunuz:
137, Seviye 16, Durum 1, Satır 19
Skaler değişkeni "@foo" olarak bildirmelidir.
Uyumluluk seviyesini yükseltmek veya sonuçları farklı bir yoldan almak dışında, başımın üstünden gerçekten iyi bir çözüm gelmiyor.
APPLY'de nitelikli sütun adlarını kullanma
90 uyumluluk modunda ve daha fazlasını yaparken, bunu sorunsuzca yapabilirsiniz:
SELECT * FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;
Bununla birlikte, 80 uyumluluk modunda, işleve verilen nitelikli sütun genel bir sözdizimi hatası oluşturur:
Mesaj 102, Seviye 15, Durum 1
'.' Yakınında yanlış sözdizimi.
Sütun adıyla eşleşen bir diğer adı SİPARİŞ VER
Bu sorguyu düşünün:
SELECT name = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.name;
80 uyumluluk modunda, sonuçlar aşağıdaki gibidir:
001_ofni_epytatad_ps sp_datatype_info_100
001_scitsitats_ps sp_statistics_100
001_snmuloc_corps_ps sp_sproc_columns_100
...
90 uyumluluk modunda, sonuçlar oldukça farklıdır:
snmuloc_lla all_columns
stcejbo_lla all_objects
sretemarap_lla all_parameters
...
Sebep? 80 uyumluluk modunda, tablo öneki tamamen göz ardı edilir, bu nedenle SELECT
listede takma ad tarafından tanımlanan ifadeye göre sıralanır . Daha yeni uyumluluk seviyelerinde, tablo öneki göz önünde bulundurulur, bu nedenle SQL Server gerçekte tablodaki bu sütunu kullanır (eğer bulunursa). Eğer ORDER BY
takma tabloda bulunamazsa, yeni uyumluluğu düzeyleri çok belirsizlik hakkında bağışlayıcı değildir. Bu örneği düşünün:
SELECT myname = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.myname;
Sonuç myname
80'deki ifade ile sıralanır , çünkü yine tablo öneki yoksayılır, ancak 90'da bu hata iletisini oluşturur:
Mesaj 207, Seviye 16, Durum 1, Satır 3
Geçersiz sütun adı 'myname'.
Bunların hepsi belgelerde de açıklanmıştır :
ORDER BY
Listedeki sütun referanslarını listede tanımlanan sütunlara bağlarken SELECT
, sütun belirsizlikleri yoksayılır ve sütun önekleri bazen yoksayılır. Bu, sonuç kümesinin beklenmedik bir sırada dönmesine neden olabilir.
Örneğin, bir SELECT listesindeki bir sütuna referans olarak kullanılan, ORDER BY
tek bir iki parçalı sütuna ( <table_alias>.<column>
) sahip bir cümle kabul edilir, ancak takma ad yoksayılır. Aşağıdaki sorguyu düşünün.
SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1
Yürütüldüğünde, sütun öneki ORDER BY
. Sıralama işlemi, x.c1
beklendiği gibi belirtilen kaynak sütunda ( ) gerçekleşmez; bunun yerine türetilmişc1
sorguda tanımlanan sütun. Bu sorgu için yürütme planı, türetilmiş sütun için değerlerin önce hesaplandığını ve sonra hesaplanan değerlerin sıralandığını gösterir.
SELECT listesinde olmayan bir şeyi SİPARİŞ VER
90 uyumluluk modunda bunu yapamazsınız:
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;
Sonuç:
Mesaj 104, Seviye 16, Durum 1
SİPARİŞ, KESİNLİK veya HARİCİ bir işleç içeriyorsa, seçim listesinde SİPARİŞ BY öğeleri görünmelidir.
80 yılında, yine de, bu sözdizimini kullanabilirsiniz.
Eski, sert dış bağlantılar
80 modu ayrıca eski, kullanımdan kaldırılmış dış birleşim sözdizimini ( *=/=*
) kullanmanıza izin verir :
SELECT o.name, c.name
FROM sys.objects AS o, sys.columns AS c
WHERE o.[object_id] *= c.[object_id];
SQL Server 2008/2008 R2’de, 90 yaşından büyükseniz, bu ayrıntılı mesajı alırsınız:
Msj 4147, Seviye 15, Durum 1
Sorgu, ANSI dışı harici birleştirme işleçlerini (" *=
" veya " =*
") kullanır. Bu sorguyu değiştirmeden çalıştırmak için, lütfen ALTER DATABASE SET COMPATIBILITY_LEVEL seçeneğini kullanarak mevcut veritabanının uyumluluk düzeyini 80 olarak ayarlayın. Sorgu ANSI dış birleştirme işleçlerini (LEFT OUTER JOIN, RIGHT OUTER JOIN) kullanarak yeniden yazmanız önemle önerilir. SQL Server'ın gelecekteki sürümlerinde, ANSI olmayan birleştirme işleçleri geriye dönük uyumluluk modlarında bile desteklenmeyecek.
SQL Server 2012'de, bu artık geçerli bir sözdizimi değildir ve aşağıdakileri sağlar:
Mesaj 102, Seviye 15, Durum 1, Satır 3
'* =' yakınında yanlış sözdizimi.
Tabii ki SQL Server 2012'de, artık 80 desteklenmediğinden uyumluluk seviyesini kullanarak bu soruna geçici bir çözüm bulamıyorsunuz. Bir veritabanını 80 uyumlu modda (yerinde yükseltme, ayırma / takma, yedekleme / geri yükleme, günlük gönderme, yansıtma vb.) Yükseltirseniz, sizin için otomatik olarak 90'a yükseltilir.
İLE olmadan Tablo ipuçları
80 uyumlu modda, aşağıdakileri kullanabilirsiniz; tablo ipucu gözlenecektir:
SELECT * FROM dbo.whatever NOLOCK;
90 + 'da, bu NOLOCK
artık bir masa ipucu değil, bir takma addır. Aksi takdirde, bu işe yarar:
SELECT * FROM dbo.whatever AS w NOLOCK;
Ama öyle değil:
1018, Seviye 15, Durum 1
'NOLOCK' yakınında yanlış sözdizimi. Bu tablo ipucunun bir parçası olarak tasarlandıysa, A WITH anahtar sözcüğü ve parantez gerekir. Doğru sözdizimi için SQL Server Books Online'da bakın.
Şimdi, davranışın ilk örnekte 90 uyumluluk modunda gözlenmediğini kanıtlamak için, AdventureWorks'ü kullanın (daha yüksek bir uyumluluk düzeyinde olduğundan emin olun) ve şunları çalıştırın:
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;
Bu özellikle problemlidir çünkü davranış bir hata mesajı veya hatta bir hata olmadan değişir. Ayrıca yükseltme danışmanı ve diğer araçların bile fark edemeyeceği bir şey, çünkü tüm bildiği için bu bir masa takma adı.
Yeni tarih / saat türlerini içeren dönüşümler
SQL Server 2008'de tanıtılan yeni tarih / saat türleri (örn. date
Ve datetime2
) orijinalden daha büyük bir aralığı desteklemektedir datetime
ve smalldatetime
). Desteklenen aralık dışındaki değerlerin açıkça dönüştürülmesi, uyumluluk düzeyi ne olursa olsun başarısız olur, örneğin:
SELECT CONVERT(SMALLDATETIME, '00010101');
Verim:
Mesaj 242, Seviye 16, Durum 3
Varchar veri tipinin smalldatetime veri tipine dönüştürülmesi, aralık dışı bir değere yol açtı.
Ancak, örtük dönüşümler daha yeni uyumluluk düzeylerinde işe yarayacak. Örneğin bu 100+ çalışacak:
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
Fakat 80'de (ve 90'da), yukarıdakiyle benzer bir hata veriyor:
Mesaj 242, Seviye 16, Durum 3
Bir varchar veri tipinin bir tarih-saat veri tipine dönüştürülmesi, aralık dışı bir değere yol açtı.
Tetikleyicilerdeki gereksiz FOR cümleleri
Bu, buraya gelen karanlık bir senaryo . 80 uyumluluk modunda bu başarılı olacaktır:
CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;
90 uyumluluk ve daha yüksek sürümlerde, bu artık ayrışmaz ve bunun yerine aşağıdaki hata iletisini alırsınız:
Mesaj 1034, Seviye 15, Durum 1, Prosedür tx
Sözdizimi hatası: Tetikleyici bildiriminde "GÜNCELLEME" eyleminin yinelenen belirtimi.
MİL / UNPIVOT
Bazı sözdizimi formları 80 yaşın altında çalışmaz (ancak 90+ da iyi çalışır):
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
Bu verim:
Mesaj 156, Seviye 15, Durum 1
'for' anahtar sözcüğünün yanında yanlış sözdizimi.
Dahil olmak üzere bazı geçici çözümler CROSS APPLY
için bu cevaplara bakın .
Yeni yerleşik fonksiyonlar
TRY_CONVERT()
Uyumluluk düzeyi <110 olan bir veritabanında olduğu gibi yeni işlevler kullanmayı deneyin . Orada hiç tanınmazlar.
SELECT TRY_CONVERT(INT, 1);
Sonuç:
Mesaj 195, Seviye 15, Durum 10
'TRY_CONVERT' tanınmış bir yerleşik işlev adı değil.
Öneri
Sadece gerçekten ihtiyacınız varsa 80 uyumluluk modunu kullanın . 2008 R2’den sonraki sürümde artık kullanılamayacağından, yapmak istediğiniz son şey, bu uyumluluk düzeyinde kod yazmak, gördüğünüz davranışlara güvenmek ve artık yapamadığınızda bir sürü kırılmaya maruz kalmaktır. bu uyumluluk seviyesini kullanın. İleriye dönük düşünün ve eski, kullanımdan kaldırılmış sözdizimini kullanmaya devam etmek için zaman satın alarak kendinizi bir köşeye boyamaya çalışmayın.