에서 워드 프로세서 :
특정 데이터베이스 동작이 지정된 버전의 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"를 선언해야합니다.
compat 수준을 업그레이드하거나 다른 방법으로 결과를 얻는 것 외에는 내 머리 꼭대기에서 실제로 좋은 해결 방법이 아닙니다.
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
'.'근처의 구문이 잘못되었습니다.
열 이름과 일치하는 별명으로 ORDER BY
이 쿼리를 고려하십시오.
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
잘못된 열 이름 'myname'입니다.
이것은 모두 문서 에 설명되어 있습니다 .
ORDER BY
목록 의 열 참조를 목록에 정의 된 열에 바인딩하면 열 SELECT
모호성이 무시되고 열 접두사가 무시되는 경우가 있습니다. 결과 집합이 예기치 않은 순서로 반환 될 수 있습니다.
예를 들어, SELECT 목록의 열에 대한 참조로 사용되는 ORDER BY
단일 두 부분 열 ( <table_alias>.<column>
)이 있는 절 은 허용되지만 테이블 별명은 무시됩니다. 다음 쿼리를 고려하십시오.
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;
결과:
문에 UNION, INTERSECT 또는 EXCEPT 연산자가 포함 된 경우 메시지 104, 수준 16, 상태 1
ORDER BY 항목이 선택 목록에 나타나야합니다.
그러나 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 이상인 경우 다음과 같은 자세한 메시지가 표시됩니다.
메시지 4147, 수준 15, 상태 1
쿼리는 ANSI 이외의 외부 조인 연산자 ( " *=
"또는 " =*
")를 사용합니다. 이 쿼리를 수정하지 않고 실행하려면 ALTER DATABASE의 SET COMPATIBILITY_LEVEL 옵션을 사용하여 현재 데이터베이스의 호환성 수준을 80으로 설정하십시오. ANSI 외부 조인 연산자 (LEFT OUTER JOIN, RIGHT OUTER JOIN)를 사용하여 쿼리를 다시 작성하는 것이 좋습니다. 이후 버전의 SQL Server에서는 비 ANSI 조인 연산자는 이전 버전과의 호환성 모드에서도 지원되지 않습니다.
SQL Server 2012에서는 이것이 더 이상 유효한 구문이 아니며 다음을 생성합니다.
메시지 102, 수준 15, 상태 1, 줄 3
'* ='근처의 구문이 잘못되었습니다.
물론 SQL Server 2012에서는 호환성 수준을 사용하여이 문제를 더 이상 해결할 수 없습니다. 80은 더 이상 지원되지 않기 때문입니다. 현재 위치 업그레이드, 분리 / 연결, 백업 / 복원, 로그 전달, 미러링 등 80 개 호환 모드에서 데이터베이스를 업그레이드하면 자동으로 90으로 업그레이드됩니다.
WITH없이 테이블 힌트
80 compat 모드에서는 다음을 사용할 수 있으며 테이블 힌트가 나타납니다.
SELECT * FROM dbo.whatever NOLOCK;
90 NOLOCK
이상에서는 더 이상 표 힌트가 아니며 별칭입니다. 그렇지 않으면 다음과 같이 작동합니다.
SELECT * FROM dbo.whatever AS w NOLOCK;
그러나 그렇지 않습니다 :
메시지 1018, 수준 15, 상태 1
'NOLOCK'근처의 구문이 잘못되었습니다. 이것이 테이블 힌트의 일부로 의도 된 경우 이제 WITH 키워드와 괄호가 필요합니다. 적절한 구문은 SQL Server 온라인 설명서를 참조하십시오.
이제 90 compat 모드에서 첫 번째 예제에서 동작이 관찰되지 않음을 증명하려면 AdventureWorks를 사용하여 (높은 compat 수준에 있는지 확인) 다음을 실행하십시오.
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');
수율 :
메시지 242, 수준 16, 상태 3
varchar 데이터 형식을 smalldatetime 데이터 형식으로 변환하면 범위를 벗어난 값이 발생했습니다.
그러나 암시 적 변환은 새로운 호환성 수준에서 스스로 작동합니다. 예를 들어 100 이상에서 작동합니다.
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
그러나 80 (및 90)에서도 위와 유사한 오류가 발생합니다.
메시지 242, 수준 16, 상태 3
varchar 데이터 형식을 날짜 / 시간 데이터 형식으로 변환하면 범위를 벗어난 값이 발생했습니다.
트리거의 중복 FOR 절
이것은 여기에 나온 모호한 시나리오입니다 . 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 이상이면 더 이상 구문 분석되지 않고 대신 다음 오류 메시지가 표시됩니다.
메시지 1034, 수준 15, 상태 1, 절차 tx
구문 오류 : 트리거 선언에서 "UPDATE"작업의 사양이 중복되었습니다.
피봇 / UNPIVOT
일부 구문 형식은 80 미만에서는 작동하지 않지만 90 이상에서는 정상적으로 작동합니다.
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
결과는 다음과 같습니다.
메시지 156, 수준 15, 상태 1
키워드 'for'근처의 구문이 잘못되었습니다.
를 포함한 일부 해결 방법 CROSS APPLY
은 다음 답변을 참조하십시오 .
새로운 내장 기능
TRY_CONVERT()
호환성 수준 <110 인 데이터베이스와 같은 새로운 기능을 사용해보십시오 . 전혀 인식되지 않습니다.
SELECT TRY_CONVERT(INT, 1);
결과:
메시지 195, 수준 15, 상태 10
'TRY_CONVERT'은 (는) 인식 된 기본 제공 함수 이름이 아닙니다.
추천
실제로 필요한 경우에만 80 호환 모드를 사용 하십시오. 2008 R2 이후의 다음 버전에서는 더 이상 사용할 수 없으므로 마지막으로 수행하려는 작업은이 호환성 수준에서 코드를 작성하고 사용자가 보는 동작에 의존 한 다음 더 이상 할 수 없을 때 완전히 파손 된 것입니다. 그 동료 수준을 사용하십시오. 앞으로 생각하고 오래되고 더 이상 사용되지 않는 구문을 계속 사용하기 위해 시간을 벌어 구석에 자신을 페인트하려고하지 마십시오.