Solucionar errores y advertencias en las expresiones de consultas

En ocasiones, SQL Server 2008 evalúa las expresiones de las consultas antes que SQL Server 2000. Este comportamiento ofrece algunas ventajas importantes:

  • Se pueden establecer coincidencias entre los índices de las columnas calculadas y las expresiones de una consulta que son iguales que la expresión de la columna calculada.

  • Se evita el cálculo redundante de los resultados de la expresión.

Sin embargo, dependiendo de la naturaleza de la consulta y de los datos de la base de datos, pueden producirse excepciones en tiempo de ejecución en SQL Server 2008 si la consulta incluye una expresión que no es segura. Entre estas excepciones en tiempo de ejecución se incluyen:

  • Excepciones aritméticas: división por cero, desbordamiento y subdesbordamiento.

  • Errores de conversión, como la pérdida de precisión y el intento de convertir una cadena no numérica en un número.

  • Agregación sobre un conjunto de valores donde no está garantizado que todos sean distintos de NULL.

Es posible que estas mismas excepciones no se produzcan en una aplicación específica con datos específicos en SQL Server 2000. Sin embargo, un plan de consulta que se cambie debido a cambios de estadística podría producir una excepción en SQL Server 2008. Estas excepciones en tiempo de ejecución se pueden evitar modificando la consulta para que incluya expresiones condicionales como NULLIF o CASE.

Nota importanteImportante

Las expresiones incluidas en una condición de búsqueda, lista de selección o cualquier otra ubicación dentro de una consulta, pueden dividirse y reorganizarse en una o varias expresiones independientes. SQL Server puede evaluar estas expresiones independientes en cualquier orden. Las operaciones de filtrado, incluidas las combinaciones, no se aplican necesariamente antes de calcular las columnas de resultados.

En este ejemplo, la expresión de la lista de selección x/y puede evaluarse en cualquier momento, incluso para las filas que finalmente no cumplen las condiciones necesarias para ser consideradas como salida de la consulta.

USE tempdb
GO
IF OBJECT_ID('T','U') IS NOT NULL
    DROP TABLE T
IF OBJECT_ID('S','U') IS NOT NULL
    DROP TABLE S
GO
CREATE TABLE T(x float, y float, z nvarchar(30))
CREATE TABLE S(a float, b float)
GO
INSERT INTO T VALUES (1, 0, 'unknown')
INSERT INTO T VALUES(1, 2, '10')
GO
INSERT INTO S VALUES (1, 1)
INSERT INTO S VALUES (1, 2)
INSERT INTO S VALUES (1, 3)
INSERT INTO S VALUES (1, 4)
INSERT INTO S VALUES (1, 5)

La siguiente consulta genera un error en SQL Server 2008, pero finaliza en SQL Server 2000.

SELECT x/y FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

La consulta no es satisfactoria porque la expresión x/y provoca un error de división por cero cuando se evalúa para y=0.

A continuación se muestra el código para que la consulta se ejecute correctamente:

SELECT x/NULLIF(y,0) FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

La expresión NULLIF(y,0) devuelve NULL si y = 0. De lo contrario, la expresión devuelve el valor para y. La expresión x/NULL da como resultado NULL y no se produce ninguna excepción.

Considere el siguiente ejemplo que incluye la conversión de datos de carácter a tipos numéricos.

SELECT CONVERT(tinyint, z) FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

La consulta genera un error de conversión cuando intenta convertir la cadena 'unknown' a tinyint. Este problema se puede solucionar modificando la consulta para que realice la conversión sólo si z es numeric. A tal efecto, incluya la instrucción CASE de la siguiente manera:

SELECT CASE WHEN ISNUMERIC(z) = 1
    THEN CONVERT(tinyint, z) 
    ELSE 0 
END
FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

Una segunda solución consiste en no utilizar el valor de cadena especial 'unknown' en la base de datos y utilizar NULL en su lugar. Una tercera solución consiste en cambiar el tipo de la columna z a tinyint y evitar la conversión por completo. Puesto que este tipo de soluciones requiere cambios en los datos y los esquemas respectivamente, puede generar más trabajo que la modificación de la consulta. No obstante, considere la posibilidad de aplicarlas si también facilitan la escritura de otras consultas.

Advertencia de entrada NULL emitida por las funciones de agregado

Las funciones de agregado, como MIN, emiten una advertencia de que se ha eliminado un valor NULL si su entrada contiene un valor NULL. Esta advertencia depende de cada plan. Si no desea procesar las entradas NULL en el agregado y no desea emitir una advertencia, puede modificar la consulta localmente para eliminar los valores NULL. Considere la instrucción SELECT en el siguiente ejemplo:

USE tempdb
GO
IF OBJECT_ID('newtitles','U') IS NOT NULL
....DROP TABLE newtitles 
GO
CREATE TABLE dbo.newtitles 
   (title varchar (80) NULL ,
    pubdate datetime NULL)
GO
INSERT dbo.newtitles VALUES('Title 1', NULL)
INSERT dbo.newtitles VALUES('Title 2', '20050311')
GO
SELECT t.title, t.pubdate, m.min_pubdate
FROM newtitles AS t,
   (SELECT MIN(pubdate) AS min_pubdate 
    FROM newtitles) AS m
WHERE t.pubdate = m.min_pubdate
GO

En SQL Server 2008, esta consulta genera una advertencia. Para evitar la advertencia, cambie la consulta agregando la condición WHERE pubdate IS NOT NULL para filtrar los valores NULL antes de la agregación:

SELECT t.title, t.pubdate, m.min_pubdate
FROM newtitles AS t,
   (SELECT MIN(pubdate) AS min_pubdate 
    FROM newtitles
    WHERE pubdate IS NOT NULL) AS m
WHERE t.pubdate = m.min_pubdate
GO

Vea también

Otros recursos