Từ các tài liệu :
Đặt các hành vi cơ sở dữ liệu nhất định để tương thích với phiên bản SQL Server được chỉ định.
...
Mức độ tương thích chỉ cung cấp khả năng tương thích ngược một phần với các phiên bản SQL Server trước đó. Sử dụng cấp độ tương thích làm trợ giúp di chuyển tạm thời để khắc phục sự khác biệt của phiên bản trong các hành vi được kiểm soát bởi cài đặt cấp độ tương thích có liên quan.
Theo cách hiểu của tôi, chế độ tương thích là về hành vi và phân tích cú pháp, không dành cho những thứ như trình phân tích cú pháp nói, "Này, bạn không thể sử dụng ROW_NUMBER()
!" Đôi khi, mức độ tương thích thấp hơn cho phép bạn tiếp tục thoát khỏi cú pháp không còn được hỗ trợ và đôi khi nó ngăn bạn sử dụng các cấu trúc cú pháp mới. Tài liệu liệt kê một số ví dụ rõ ràng, nhưng đây là một vài minh chứng:
Truyền các hàm dựng sẵn làm đối số hàm
Mã này hoạt động ở mức tương thích 90+:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);
Nhưng vào năm 80, nó mang lại:
Msg 102, Cấp 15, Trạng thái 1
Cú pháp không chính xác gần '('.
Vấn đề cụ thể ở đây là trong 80 bạn không được phép chuyển một hàm tích hợp vào một hàm. Nếu bạn muốn ở trong chế độ tương thích 80, bạn có thể giải quyết vấn đề này bằng cách nói:
DECLARE @db_id INT = DB_ID();
SELECT *
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);
Truyền loại bảng cho hàm có giá trị bảng
Tương tự như trên, bạn có thể gặp lỗi cú pháp khi sử dụng TVP và cố gắng chuyển nó sang hàm có giá trị bảng. Điều này hoạt động ở cấp độ compat hiện đại:
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);
Tuy nhiên, thay đổi mức độ tương thích thành 80 và chạy lại ba dòng cuối cùng; bạn nhận được thông báo lỗi này:
Msg 137, Cấp 16, Trạng thái 1, Dòng 19
Phải khai báo biến vô hướng "@foo".
Không thực sự có bất kỳ cách giải quyết tốt nào ngoài đỉnh đầu của tôi, ngoài việc nâng cấp cấp độ compat hoặc nhận kết quả theo một cách khác.
Sử dụng tên cột đủ điều kiện trong ỨNG DỤNG
Trong 90 chế độ tương thích trở lên, bạn có thể thực hiện việc này mà không gặp vấn đề gì:
SELECT * FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;
Tuy nhiên, trong chế độ tương thích 80, cột đủ điều kiện được trao cho hàm sẽ phát sinh lỗi cú pháp chung:
Msg 102, Cấp 15, Trạng thái 1
Cú pháp không chính xác gần '.'.
ĐẶT HÀNG theo một bí danh xảy ra khớp với tên cột
Xem xét truy vấn này:
SELECT name = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.name;
Trong chế độ tương thích 80, kết quả như sau:
001_ofni_epytatad_ps sp_datatype_info_100
001_scitsitats_ps sp_statistics_100
001_snmuloc_corps_ps sp_sproc_columns_100
...
Trong chế độ tương thích 90, kết quả khá khác nhau:
snmuloc_lla all_columns
stcejbo_lla all_objects
sretemarap_lla all_parameters
...
Nguyên nhân? Trong chế độ tương thích 80, tiền tố bảng bị bỏ qua hoàn toàn, do đó, nó được sắp xếp theo biểu thức được xác định bởi bí danh trong SELECT
danh sách. Trong các mức độ tương thích mới hơn, tiền tố của bảng được xem xét, vì vậy SQL Server sẽ thực sự sử dụng cột đó trong bảng (nếu nó được tìm thấy). Nếu ORDER BY
không tìm thấy bí danh trong bảng, các mức tương thích mới hơn sẽ không tha thứ cho sự mơ hồ. Xem xét ví dụ này:
SELECT myname = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.myname;
Kết quả được sắp xếp theo myname
biểu thức trong 80, vì một lần nữa tiền tố bảng bị bỏ qua, nhưng trong 90, nó tạo ra thông báo lỗi này:
Msg 207, Cấp 16, Bang 1, Dòng 3
Tên cột không hợp lệ 'myname'.
Điều này cũng được giải thích trong tài liệu :
Khi liên kết các tham chiếu cột trong ORDER BY
danh sách với các cột được xác định trong SELECT
danh sách, sự mơ hồ của cột bị bỏ qua và các tiền tố cột đôi khi bị bỏ qua. Điều này có thể khiến kết quả được đặt trở lại theo thứ tự không mong muốn.
Ví dụ: một ORDER BY
mệnh đề có một cột hai phần ( <table_alias>.<column>
) được sử dụng làm tham chiếu đến một cột trong danh sách CHỌN được chấp nhận, nhưng bí danh bảng bị bỏ qua. Hãy xem xét các truy vấn sau đây.
SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1
Khi được thực thi, tiền tố cột bị bỏ qua trong ORDER BY
. Hoạt động sắp xếp không xảy ra trên cột nguồn được chỉ định ( x.c1
) như mong đợi; thay vào đó nó xảy ra trên dẫn xuấtc1
cột được xác định trong truy vấn. Kế hoạch thực hiện cho truy vấn này cho thấy rằng các giá trị cho cột dẫn xuất được tính toán trước và sau đó các giá trị được tính toán được sắp xếp.
ĐẶT HÀNG THEO một cái gì đó không có trong danh sách CHỌN
Trong chế độ tương thích 90, bạn không thể làm điều này:
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;
Kết quả:
Msg 104, Cấp 16, Trạng thái 1
ĐẶT HÀNG theo các mục phải xuất hiện trong danh sách chọn nếu câu lệnh chứa toán tử UNION, INTERSECT hoặc EXCEPT.
Tuy nhiên, trong 80, bạn vẫn có thể sử dụng cú pháp này.
Cũ, bên ngoài icky tham gia
Chế độ 80 cũng cho phép bạn sử dụng cú pháp nối ngoài cũ, không dùng nữa ( *=/=*
):
SELECT o.name, c.name
FROM sys.objects AS o, sys.columns AS c
WHERE o.[object_id] *= c.[object_id];
Trong SQL Server 2008/2008 R2, nếu bạn ở độ tuổi 90 trở lên, bạn sẽ nhận được thông báo dài dòng này:
Msg 4147, Cấp 15, Trạng thái 1
Truy vấn sử dụng các toán tử nối ngoài không ANSI (" *=
" hoặc " =*
"). Để chạy truy vấn này mà không cần sửa đổi, vui lòng đặt mức độ tương thích cho cơ sở dữ liệu hiện tại thành 80, bằng cách sử dụng tùy chọn SET COMPATITALITY_LEVEL của ALTER DATABASE. Chúng tôi khuyên bạn nên viết lại truy vấn bằng cách sử dụng các toán tử nối ngoài ANSI (LEFT OUTER THAM GIA, RIGHT OUTER THAM GIA). Trong các phiên bản tương lai của SQL Server, các toán tử tham gia không ANSI sẽ không được hỗ trợ ngay cả trong các chế độ tương thích ngược.
Trong SQL Server 2012, đây không còn là cú pháp hợp lệ nữa và mang lại kết quả như sau:
Msg 102, Cấp 15, Trạng thái 1, Dòng 3
Cú pháp không chính xác gần '* ='.
Tất nhiên trong SQL Server 2012, bạn không còn có thể giải quyết vấn đề này bằng mức độ tương thích, vì 80 không còn được hỗ trợ. Nếu bạn nâng cấp cơ sở dữ liệu ở chế độ 80 compat (bằng cách nâng cấp tại chỗ, tách / đính kèm, sao lưu / khôi phục, vận chuyển nhật ký, phản chiếu, v.v.), nó sẽ tự động được nâng cấp lên 90 cho bạn.
Gợi ý bảng mà không CÓ
Trong chế độ 80 compat, bạn có thể sử dụng như sau và gợi ý bảng sẽ được quan sát:
SELECT * FROM dbo.whatever NOLOCK;
Trong 90+, đó NOLOCK
không còn là gợi ý bảng nữa, đó là bí danh. Nếu không, điều này sẽ làm việc:
SELECT * FROM dbo.whatever AS w NOLOCK;
Nhưng nó không:
Msg 1018, Cấp 15, Trạng thái 1
Cú pháp không chính xác gần 'NOLOCK'. Nếu điều này được dự định là một phần của gợi ý bảng, thì từ khóa A và dấu ngoặc đơn hiện đang được yêu cầu. Xem Sách SQL Server trực tuyến để biết cú pháp thích hợp.
Bây giờ, để chứng minh rằng hành vi không được quan sát trong ví dụ đầu tiên khi ở chế độ 90 compat, hãy sử dụng AdventureWorks (đảm bảo rằng nó ở mức độ tương thích cao hơn) và chạy như sau:
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;
Điều này đặc biệt có vấn đề vì hành vi thay đổi mà không có thông báo lỗi hoặc thậm chí là lỗi. Và đó cũng là điều mà trình cố vấn nâng cấp và các công cụ khác thậm chí có thể không phát hiện ra, vì đối với tất cả những gì nó biết, đó là bí danh bảng.
Chuyển đổi liên quan đến các loại ngày / giờ mới
Các loại ngày / giờ mới được giới thiệu trong SQL Server 2008 (ví dụ date
và datetime2
) hỗ trợ phạm vi lớn hơn nhiều so với bản gốc datetime
và smalldatetime
). Chuyển đổi rõ ràng các giá trị ngoài phạm vi được hỗ trợ sẽ không thành công cho dù mức độ tương thích là gì, ví dụ:
SELECT CONVERT(SMALLDATETIME, '00010101');
Sản lượng:
Msg 242, Cấp 16, Trạng thái 3
Việc chuyển đổi loại dữ liệu varchar thành loại dữ liệu thời gian nhỏ dẫn đến một giá trị ngoài phạm vi.
Tuy nhiên, chuyển đổi ngầm sẽ tự giải quyết ở các cấp độ tương thích mới hơn. Ví dụ: điều này sẽ hoạt động trong hơn 100:
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
Nhưng vào năm 80 (và cả năm 90), nó cũng gây ra lỗi tương tự như trên:
Msg 242, Cấp 16, Trạng thái 3
Việc chuyển đổi loại dữ liệu varchar thành loại dữ liệu datetime dẫn đến giá trị ngoài phạm vi.
Điều khoản dự phòng cho các điều khoản kích hoạt
Đây là một kịch bản tối nghĩa xuất hiện ở đây . Trong chế độ tương thích 80, điều này sẽ thành công:
CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;
Trong 90 khả năng tương thích và cao hơn, điều này không còn phân tích cú pháp nữa và thay vào đó bạn nhận được thông báo lỗi sau:
Msg 1034, Cấp 15, Trạng thái 1, Quy trình tx
Lỗi cú pháp: Đặc tả trùng lặp của hành động "CẬP NHẬT" trong khai báo kích hoạt.
PIVOT / UNPIVOT
Một số dạng cú pháp sẽ không hoạt động dưới 80 (nhưng chỉ hoạt động tốt trong 90+):
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
Sản lượng này:
Msg 156, Cấp 15, Trạng thái 1
Cú pháp không chính xác gần từ khóa 'cho'.
Đối với một số cách giải quyết, bao gồm CROSS APPLY
, xem những câu trả lời này .
Các chức năng tích hợp mới
Hãy thử sử dụng các chức năng mới như TRY_CONVERT()
trong cơ sở dữ liệu với mức độ tương thích <110. Đơn giản là chúng không được nhận ra ở đó.
SELECT TRY_CONVERT(INT, 1);
Kết quả:
Msg 195, Cấp 15, Trạng thái 10
'TRY_CONVERT' không phải là tên hàm tích hợp được công nhận.
sự giới thiệu
Chỉ sử dụng chế độ tương thích 80 nếu bạn thực sự cần nó. Vì nó sẽ không còn có sẵn trong phiên bản tiếp theo sau 2008 R2, điều cuối cùng bạn muốn làm là viết mã ở cấp độ compat này, dựa vào các hành vi bạn thấy và sau đó có cả đống vỡ khi bạn không thể sử dụng mức độ compat đó. Hãy suy nghĩ về phía trước và đừng cố vẽ mình vào một góc bằng cách mua thời gian để tiếp tục sử dụng cú pháp cũ, không dùng nữa.