De los documentos :
Establece ciertos comportamientos de la base de datos para que sean compatibles con la versión especificada de SQL Server.
... El
nivel de compatibilidad solo proporciona compatibilidad parcial con versiones anteriores de SQL Server. Utilice el nivel de compatibilidad como ayuda de migración provisional para solucionar las diferencias de versión en los comportamientos controlados por la configuración de nivel de compatibilidad relevante.
En mi interpretación, el modo de compatibilidad se trata del comportamiento y el análisis de la sintaxis, no para cosas como el analizador que dice: "¡Hey, no puedes usarlo ROW_NUMBER()
!" A veces, el nivel de compatibilidad más bajo le permite continuar evitando que la sintaxis ya no sea compatible, y a veces le impide usar nuevas construcciones de sintaxis. La documentación enumera varios ejemplos explícitos, pero aquí hay algunas demostraciones:
Pasar funciones integradas como argumentos de función
Este código funciona en el nivel de compatibilidad 90+:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);
Pero en 80 produce:
Mensaje 102, Nivel 15, Estado 1
Sintaxis incorrecta cerca de '('.
El problema específico aquí es que en 80 no se le permite pasar una función incorporada a una función. Si desea permanecer en el modo de compatibilidad 80, puede solucionar esto diciendo:
DECLARE @db_id INT = DB_ID();
SELECT *
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);
Pasar un tipo de tabla a una función con valores de tabla
Similar a lo anterior, puede obtener un error de sintaxis al usar un TVP e intentar pasarlo a una función con valores de tabla. Esto funciona en niveles de compatibilidad modernos:
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);
Sin embargo, cambie el nivel de compatibilidad a 80 y ejecute las últimas tres líneas nuevamente; obtienes este mensaje de error:
Mensaje 137, Nivel 16, Estado 1, Línea 19
Debe declarar la variable escalar "@foo".
En realidad, no es una buena solución alternativa, aparte de actualizar el nivel de compatibilidad u obtener los resultados de una manera diferente.
Usar nombres de columna calificados en APLICAR
En el modo de compatibilidad 90 y superior, puede hacer esto sin problema:
SELECT * FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;
Sin embargo, en el modo de compatibilidad 80, la columna calificada entregada a la función genera un error de sintaxis genérico:
Mensaje 102, Nivel 15, Estado 1
Sintaxis incorrecta cerca de '.'.
ORDER BY un alias que coincide con el nombre de una columna
Considere esta consulta:
SELECT name = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.name;
En el modo de compatibilidad 80, los resultados son los siguientes:
001_ofni_epytatad_ps sp_datatype_info_100
001_scitsitats_ps sp_statistics_100
001_snmuloc_corps_ps sp_sproc_columns_100
...
En el modo de compatibilidad 90, los resultados son bastante diferentes:
snmuloc_lla all_columns
stcejbo_lla all_objects
sretemarap_lla all_parameters
...
¿La razón? En el modo de compatibilidad 80, el prefijo de la tabla se ignora por completo, por lo que está ordenado por la expresión definida por el alias en la SELECT
lista. En los niveles de compatibilidad más nuevos, se considera el prefijo de la tabla, por lo que SQL Server realmente usará esa columna en la tabla (si se encuentra). Si el ORDER BY
alias no se encuentra en la tabla, los niveles de compatibilidad más nuevos no son tan indulgentes con la ambigüedad. Considere este ejemplo:
SELECT myname = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.myname;
El resultado está ordenado por la myname
expresión en 80, porque nuevamente se ignora el prefijo de la tabla, pero en 90 genera este mensaje de error:
Mensaje 207, Nivel 16, Estado 1, Línea 3
Nombre de columna no válido 'myname'.
Todo esto también se explica en la documentación :
Cuando se vinculan las referencias de columna en la ORDER BY
lista a las columnas definidas en la SELECT
lista, se ignoran las ambigüedades de columna y los prefijos de columna a veces se ignoran. Esto puede hacer que el conjunto de resultados regrese en un orden inesperado.
Por ejemplo, se acepta una ORDER BY
cláusula con una sola columna de dos partes ( <table_alias>.<column>
) que se usa como referencia a una columna en una lista SELECT, pero se ignora el alias de la tabla. Considere la siguiente consulta.
SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1
Cuando se ejecuta, el prefijo de columna se ignora en el ORDER BY
. La operación de clasificación no se produce en la columna fuente especificada ( x.c1
) como se esperaba; en cambio ocurre en el derivadoc1
columna que se define en la consulta. El plan de ejecución para esta consulta muestra que los valores de la columna derivada se calculan primero y luego se ordenan los valores calculados.
ORDER BY algo que no está en la lista SELECT
En el modo de compatibilidad 90 no puedes hacer esto:
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;
Resultado:
Los elementos Msg 104, Nivel 16, Estado 1
ORDER BY deben aparecer en la lista de selección si la declaración contiene un operador UNION, INTERSECT o EXCEPT.
Sin embargo, en 80 todavía puede usar esta sintaxis.
Uniones exteriores viejas y repulsivas
El modo 80 también le permite usar la antigua y obsoleta sintaxis de combinación externa ( *=/=*
):
SELECT o.name, c.name
FROM sys.objects AS o, sys.columns AS c
WHERE o.[object_id] *= c.[object_id];
En SQL Server 2008/2008 R2, si tiene 90 o más, recibirá este mensaje detallado:
Mensaje 4147, Nivel 15, Estado 1
La consulta utiliza operadores de combinación externa no ANSI (" *=
" o " =*
"). Para ejecutar esta consulta sin modificaciones, establezca el nivel de compatibilidad para la base de datos actual en 80, utilizando la opción SET COMPATIBILITY_LEVEL de ALTER DATABASE. Se recomienda volver a escribir la consulta utilizando operadores de combinación externa ANSI (UNIDAD EXTERIOR IZQUIERDA, UNIÓN EXTERIOR DERECHA) En las futuras versiones de SQL Server, los operadores de unión que no sean ANSI no serán compatibles incluso en los modos de compatibilidad con versiones anteriores.
En SQL Server 2012, esto ya no es una sintaxis válida y produce lo siguiente:
Mensaje 102, Nivel 15, Estado 1, Línea 3
Sintaxis incorrecta cerca de '* ='.
Por supuesto, en SQL Server 2012 ya no puede solucionar este problema utilizando el nivel de compatibilidad, ya que 80 ya no es compatible. Si actualiza una base de datos en modo de compatibilidad 80 (mediante actualización en el lugar, desconectar / adjuntar, copia de seguridad / restaurar, envío de registros, duplicación, etc.), automáticamente se actualizará a 90 para usted.
Sugerencias de tabla sin CON
En el modo de compatibilidad 80, puede usar lo siguiente y se observará la sugerencia de la tabla:
SELECT * FROM dbo.whatever NOLOCK;
En 90+, eso NOLOCK
ya no es una pista de tabla, es un alias. De lo contrario, esto funcionaría:
SELECT * FROM dbo.whatever AS w NOLOCK;
Pero no lo hace:
Mensaje 1018, Nivel 15, Estado 1
Sintaxis incorrecta cerca de 'NOLOCK'. Si esto está pensado como parte de una sugerencia de tabla, ahora se requiere una palabra clave y paréntesis A WITH. Consulte los Libros en pantalla de SQL Server para obtener la sintaxis adecuada.
Ahora, para demostrar que el comportamiento no se observa en el primer ejemplo cuando está en modo de compatibilidad 90, use AdventureWorks (asegurándose de que esté en un nivel de compatibilidad más alto) y ejecute lo siguiente:
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;
Este es particularmente problemático porque el comportamiento cambia sin un mensaje de error o incluso un error. Y también es algo que el asesor de actualizaciones y otras herramientas podrían ni siquiera detectar, ya que, por lo que sabe, es un alias de tabla.
Conversiones que involucran nuevos tipos de fecha / hora
Los nuevos tipos de fecha / hora introducidos en SQL Server 2008 (por ejemplo, date
y datetime2
) admiten un rango mucho mayor que el original datetime
y smalldatetime
). Las conversiones explícitas de valores fuera del rango admitido fallarán sin importar el nivel de compatibilidad, por ejemplo:
SELECT CONVERT(SMALLDATETIME, '00010101');
Rendimientos:
Msg 242, Nivel 16, Estado 3
La conversión de un tipo de datos varchar a un tipo de datos smalldatetime dio como resultado un valor fuera de rango.
Sin embargo, las conversiones implícitas se resolverán en los niveles de compatibilidad más nuevos. Por ejemplo, esto funcionará en más de 100:
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
Pero en 80 (y también en 90), produce un error similar al anterior:
Msg 242, Nivel 16, Estado 3
La conversión de un tipo de datos varchar a un tipo de datos datetime dio como resultado un valor fuera de rango.
Cláusulas FOR redundantes en desencadenantes
Este es un escenario oscuro que surgió aquí . En el modo de compatibilidad 80, esto tendrá éxito:
CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;
En 90 compatibilidad y superior, esto ya no se analiza, y en su lugar aparece el siguiente mensaje de error:
Mensaje 1034, Nivel 15, Estado 1, Procedimiento tx
Error de sintaxis: especificación duplicada de la acción "ACTUALIZAR" en la declaración de activación.
PIVOTE / UNPIVOT
Algunas formas de sintaxis no funcionarán por debajo de 80 (pero funcionan bien en 90+):
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
Esto produce:
Mensaje 156, Nivel 15, Estado 1
Sintaxis incorrecta cerca de la palabra clave 'para'.
Para algunas soluciones, incluso CROSS APPLY
, vea estas respuestas .
Nuevas funciones integradas
Intente usar nuevas funciones como TRY_CONVERT()
en una base de datos con un nivel de compatibilidad <110. Simplemente no se reconocen allí en absoluto.
SELECT TRY_CONVERT(INT, 1);
Resultado:
Mensaje 195, Nivel 15, Estado 10
'TRY_CONVERT' no es un nombre de función incorporado reconocido.
Recomendación
Solo use el modo de compatibilidad 80 si realmente lo necesita. Dado que ya no estará disponible en la próxima versión después de 2008 R2, lo último que desea hacer es escribir código en este nivel de compatibilidad, confiar en los comportamientos que ve y luego tener un montón de roturas cuando ya no pueda usa ese nivel de compatibilidad. Sea progresista y no intente pintarse en una esquina al ganar tiempo para seguir usando una sintaxis antigua y obsoleta.