Solucionando erros e avisos em expressões de consulta

Algumas vezes, o SQL Server 2008 avalia expressões em consultas antes do SQL Server 2000. Esse comportamento fornece os seguintes importantes benefícios:

  • Índices em colunas computadas podem ser comparados a expressões, em uma consulta, que sejam as mesmas que a expressão da coluna computada.

  • A computação redundante dos resultados da expressão é evitada.

Porém, dependendo da natureza da consulta e dos dados no banco de dados, exceções em tempo de execução poderão ocorrer no SQL Server 2008 se a consulta contiver uma expressão existente não segura. Essas exceções em tempo de execução incluem o seguinte:

  • Exceções aritméticas de: divisão por zero, estouro de capacidade e estouro negativo.

  • Falhas de conversão como perda de precisão e uma tentativa de converter uma cadeia de caracteres não numérica em número.

  • Agregação em um conjunto de valores não garantidos como nonnull.

No SQL Server 2000, essas exceções podem não ocorrer em um aplicativo específico que usa dados específicos. No entanto, um plano de consulta que é alterado, devido a mudanças na estatística, poderia potencialmente conduzir a uma exceção no SQL Server 2008. Você pode evitar essas exceções em tempo de execução modificando a consulta para que ela inclua expressões condicionais como NULLIF ou CASE.

Observação importanteImportante

Expressões que aparecem em um critério de pesquisa, em uma lista de seleção ou em qualquer outro local em uma consulta podem ser divididas e reorganizadas em uma ou mais expressões independentes. O SQL Server pode avaliar essas expressões independentes em qualquer ordem em relação uma com a outra. Operações de filtragem, incluindo junções, não são necessariamente aplicadas antes que as colunas resultantes sejam computadas.

No exemplo a seguir, a expressão x/y na lista selecionada pode ser avaliada a qualquer momento, mesmo em linhas que, essencialmente, não se qualificam como saída para a 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)

A consulta a seguir falha no SQL Server 2008, mas é concluída no SQL Server 2000.

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

A consulta falha porque a expressão x/y causa um erro de divisão por zero quando a expressão é avaliada para y=0.

O código a seguir é uma solução que permite que a consulta seja executada corretamente:

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

A expressão NULLIF(y,0) retorna NULL se y = 0. Caso contrário, a expressão retornará o valor para y. A expressão x/NULL produz NULL e não ocorrem exceções.

Considere o exemplo a seguir, que envolve a conversão de dados de caracteres em tipos numéricos.

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

A consulta falha com um erro de conversão quando tenta converter a cadeia de caracteres 'unknown' em um tinyint. Uma forma de resolver esse problema é modificar a consulta para executar a conversão somente se z for numeric, introduzindo uma instrução CASE como:

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)

Uma segunda solução é abrir mão de usar o valor de cadeia de caracteres especial 'unknown' no banco de dados e usar NULL. Uma terceira solução é alterar o tipo da coluna z para tinyint para evitar completamente a conversão. Como soluções como essas requerem alterações de dados e esquema, respectivamente, a aplicação dessas soluções pode envolver mais trabalho do que modificar a consulta. No entanto, recomendamos que considere essas soluções se elas facilitarem também a gravação de outras consultas.

Aviso de entrada de NULL emitido por funções de agregação

Funções de agregação, como MIN, emitirão um aviso de que um valor nulo foi eliminado, se suas entradas contiverem um NULL. Esse aviso pode depender do plano. Para que as entradas de NULL da agregação não sejam processadas e um aviso não seja emitido você pode modificar sua consulta localmente para eliminar valores nulos. Considere a instrução SELECT no seguinte exemplo:

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

No SQL Server 2008, essa consulta produz um aviso. Para evitar o aviso, altere a consulta adicionando a condição WHERE pubdate IS NOT NULL para filtrar os valores nulos antes da agregação:

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

Consulte também

Outros recursos