З документів :
Встановлює певну поведінку бази даних, сумісну з вказаною версією SQL Server.
...
Рівень сумісності забезпечує лише часткову сумісність з попередніми версіями SQL Server. Використовуйте рівень сумісності як проміжну міграційну допомогу, щоб подолати різницю версій у поведінці, які контролюються відповідними параметрами рівня сумісності.
У моєму трактуванні режим сумісності - це поведінка та аналіз синтаксису, а не для таких речей, як аналізатор, який говорить: "Ей, ти не можеш використовувати ROW_NUMBER()
!" Іноді нижчий рівень сумісності дозволяє продовжувати відходити від синтаксису, який більше не підтримується, а іноді заважає використовувати нові конструкції синтаксису. Документація перераховує кілька явних прикладів, але ось кілька демонстрацій:
Передача вбудованих функцій як аргументів функції
Цей код працює на рівні сумісності 90+:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);
Але в 80-х роках це дає:
Повідомлення 102, рівень 15, стан 1
Неправильний синтаксис біля '(').
Конкретна проблема тут полягає в тому, що в 80-х вам заборонено передавати вбудовану функцію у функцію. Якщо ви хочете залишитися в режимі сумісності 80, ви можете обійти це, сказавши:
DECLARE @db_id INT = DB_ID();
SELECT *
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);
Передача типу таблиці функції, що оцінюється за таблицею
Подібно до вищесказаного, ви можете отримати синтаксичну помилку під час використання TVP та спроби передати її функції, що оцінюється за таблицею. Це працює на сучасних рівнях compat:
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);
Однак змініть рівень сумісності на 80 та запустіть останні три рядки знову; ви отримуєте це повідомлення про помилку:
Повідомлення 137, рівень 16, стан 1, рядок 19
Повинен оголосити скалярну змінну "@foo".
Насправді не будь-який хороший спосіб вирішити мою голову, окрім покращення рівня співбесіди або отримання результатів іншим способом.
Використання кваліфікованих імен стовпців у APPLY
У режимі сумісності 90 і вище ви можете це зробити без проблем:
SELECT * FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;
Однак у режимі сумісності 80 кваліфікований стовпець, переданий функції, викликає загальну помилку синтаксису:
Повідомлення 102, рівень 15, стан 1
Неправильний синтаксис поблизу '.'
ЗАМОВИТИ псевдонім, який відповідає імені стовпця
Розглянемо цей запит:
SELECT name = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.name;
У режимі сумісності 80 результати такі:
001_ofni_epytatad_ps sp_datatype_info_100
001_scitsitats_ps sp_statistics_100
001_snmuloc_corps_ps sp_sproc_columns_100
...
У режимі сумісності 90 результати зовсім інші:
snmuloc_lla all_columns
stcejbo_lla all_objects
sretemarap_lla all_parameters
...
Причина? У режимі сумісності 80 префікс таблиці повністю ігнорується, тому він упорядковується за виразом, визначеним псевдонімом у SELECT
списку. На нових рівнях сумісності розглядається префікс таблиці, тому SQL Server фактично використовуватиме цей стовпець у таблиці (якщо він знайдений). Якщо ORDER BY
псевдонім не знайдений у таблиці, новіші рівні сумісності не так пробачать про неоднозначність. Розглянемо цей приклад:
SELECT myname = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.myname;
Результат упорядковується myname
виразом у 80, тому що знову префікс таблиці ігнорується, але в 90 він генерує це повідомлення про помилку:
Повідомлення 207, рівень 16, стан 1, рядок 3
Недійсне ім'я стовпця "моє ім'я".
Це все пояснено також у документації :
Прив’язуючи посилання стовпців у ORDER BY
списку до стовпців, визначених у SELECT
списку, неоднозначності стовпців ігноруються, а префікси стовпців іноді ігноруються. Це може призвести до повернення набору результатів у несподіваному порядку.
Наприклад, ORDER BY
пропозиція з одним двочастинним стовпцем ( <table_alias>.<column>
), який використовується як посилання на стовпець у списку SELECT, приймається, але псевдонім таблиці ігнорується. Розглянемо наступний запит.
SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1
При виконанні префікс стовпця ігнорується в ORDER BY
. Операція сортування не відбувається у вказаному стовпці джерела ( x.c1
), як очікувалося; натомість це відбувається на похідномуc1
стовпчик, який визначений у запиті. План виконання цього запиту показує, що значення для похідного стовпця спочатку обчислюються, а потім обчислюються значення.
ЗАМОВИТИ Щось, що не в списку SELECT
У режимі сумісності 90 ви не можете цього зробити:
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;
Результат:
Повідомлення 104, Рівень 16, Стан 1
ЗАМОВЛЕННЯ ПО ЕЛЕМЕНТУ повинні з'являтися у списку вибору, якщо заява містить оператора UNION, INTERSECT або EXCEPT.
У 80-му році цей синтаксис ви все ще можете використовувати.
Старий, прискіпливий зовнішній приєднується
Режим 80 також дозволяє використовувати старий, застарілий зовнішній синтаксис приєднання ( *=/=*
):
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, якщо вам виповнилося 90 років або більше, ви отримуєте це багатослівне повідомлення:
Msg 4147, рівень 15, стан 1
У запиті використовуються оператори зовнішнього з'єднання, які не є ANSI (" *=
" або " =*
"). Для запуску цього запиту без змін, будь ласка, встановіть рівень сумісності для поточної бази даних на 80, використовуючи опцію SET COMPATIBILITY_LEVEL ALTER DATABASE. Настійно рекомендується перезаписувати запит, використовуючи зовнішні оператори ANSI (приєднайтесь ліворуч, ПРИЄДНО ПРИЄДНАЙТЕСЬ). У майбутніх версіях SQL Server оператори приєднання, що не належать до ANSI, не підтримуватимуться навіть у режимах сумісності із зворотним.
У SQL Server 2012 цей синтаксис більше не є дійсним і отримує наступне:
Повідомлення 102, рівень 15, стан 1, рядок 3
Неправильний синтаксис поблизу '* ='.
Звичайно, у SQL Server 2012 ви більше не можете вирішити цю проблему, використовуючи рівень сумісності, оскільки 80 більше не підтримується. Якщо ви оновите базу даних у режимі 80 компат (за допомогою оновлення на місці, відключення / приєднання, резервного копіювання / відновлення, доставки журналу, дзеркального відображення тощо), вона автоматично буде оновлена до 90 для вас.
Підказки таблиці без З
У режимі 80 компат можна використовувати наступне, і натяк на таблицю буде дотримано:
SELECT * FROM dbo.whatever NOLOCK;
У 90+ NOLOCK
це вже не натяк на таблицю, це псевдонім. Інакше це спрацює:
SELECT * FROM dbo.whatever AS w NOLOCK;
Але це не так:
Повідомлення 1018, рівень 15, стан 1
Неправильний синтаксис біля "NOLOCK". Якщо це призначено як частина натяку на таблицю, тепер потрібні ключове слово AND дужки. Дивіться SQL Server Books Online для отримання відповідного синтаксису.
Тепер, щоб довести, що поведінка не спостерігається в першому прикладі, коли в режимі 90 компат, використовуйте AdventureWorks (переконайтесь, що вона знаходиться на більш високому рівні компат) і виконайте наступне:
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;
Це особливо проблематично, оскільки поведінка змінюється без повідомлення про помилку чи навіть про помилку. І це також те, що радник з оновлення та інші інструменти можуть навіть не помітити, оскільки, як відомо, це псевдонім таблиці.
Конверсії, що включають нові типи дати / часу
Нові типи дати / часу, введені в SQL Server 2008 (наприклад, date
та datetime2
), підтримують набагато більший діапазон, ніж оригінал datetime
та smalldatetime
). Явні перетворення значень за межами підтримуваного діапазону вийдуть з ладу, незалежно від рівня сумісності, наприклад:
SELECT CONVERT(SMALLDATETIME, '00010101');
Врожайність:
Msg 242, Рівень 16, Стан 3
Перетворення типу даних varchar у тип даних для малого часу приводило до значення поза діапазоном.
Однак неявні перетворення працюватимуть самі на нових рівнях сумісності. Наприклад, це буде працювати в 100+:
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
Але в 80 (і також в 90-х) він створює аналогічну помилку, як і вище:
Msg 242, Рівень 16, Стан 3
Перетворення типу даних varchar у тип даних дати дату призвело до значення поза діапазоном.
Надлишкові ЗА застереження в тригерах
Це незрозумілий сценарій, який з’явився тут . У режимі сумісності 80 це вдасться:
CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;
У сумісність 90 і вище це більше не аналізується, і натомість ви отримуєте таке повідомлення про помилку:
Msg 1034, рівень 15, стан 1, процедура tx
Помилка синтаксису: Дублювання специфікації дії "UPDATE" в декларації тригера.
PIVOT / UNPIVOT
Деякі форми синтаксису не працюватимуть у віці до 80 років (але працюють добре в 90+):
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
Це дає:
Повідомлення 156, рівень 15, стан 1
Неправильний синтаксис біля ключового слова "для".
Деякі вирішення проблем, зокрема CROSS APPLY
, дивіться ці відповіді .
Нові вбудовані функції
Спробуйте використовувати нові функції, наприклад, TRY_CONVERT()
у базі даних із рівнем сумісності <110. Їх просто взагалі не розпізнають.
SELECT TRY_CONVERT(INT, 1);
Результат:
Повідомлення 195, рівень 15, стан 10
'TRY_CONVERT' не є впізнаваною вбудованою функцією.
Рекомендація
Користуйтеся режимом сумісності 80 лише тоді, коли він вам справді потрібен. Оскільки він не буде доступний у наступній версії після R2 2008 року, останнє, що ви хочете зробити, - це написати код на цьому рівні співзвучності, покластися на поведінку, яку ви бачите, а потім мати цілу купу поломки, коли вже не зможете. використовувати цей рівень співзвучності. Будьте думкою вперед і не намагайтеся малювати себе в кутку, купуючи час, щоб продовжити використання старого, застарілого синтаксису.