Melhor maneira de verificar "valor vazio ou nulo"

176

Qual é a melhor maneira de verificar se o valor é nulo ou vazio nas instruções sql do Postgres?

O valor pode ser uma expressão longa, portanto é preferível que ele seja gravado apenas uma vez em cheque.

Atualmente estou usando:

coalesce( trim(stringexpression),'')=''

Mas parece um pouco feio.

stringexpressionpode ser char(n)coluna ou expressão contendo char(n)colunas com espaços à direita.

Qual é a melhor maneira?

Andrus
fonte
3
O uso charé quase sempre a escolha errada devido ao preenchimento (e ao desperdício de espaço resultante). Mas além disso: não acho que exista uma solução melhor.
A_horse_with_no_name 20/05
Por que feio? Lógico e legível.
Klin 20/05
1
@a_horse_with_no_name: Eu acho que existe.
Erwin Brandstetter

Respostas:

283

A expressão stringexpression = ''produz:

TRUE   .. for ''(ou para qualquer sequência que consiste apenas em espaços com o tipo de dados char(n))
NULL   .. forNULL
FALSE .. para qualquer outra coisa

Portanto, para verificar: " stringexpressioné NULL ou vazio" :

(stringexpression = '') IS NOT FALSE

Ou a abordagem inversa (pode ser mais fácil de ler):

(stringexpression <> '') IS NOT TRUE

Funciona para qualquer tipo de personagem, incluindo char(n). O manual sobre operadores de comparação.

Ou use sua expressão original sem trim(), que é um ruído dispendioso para char(n)(veja abaixo) ou incorreta para outros tipos de caracteres: cadeias que consistem em apenas espaços passariam como cadeias vazias.

coalesce(stringexpression, '') = ''

Mas as expressões no topo são mais rápidas.

Afirmar o contrário é ainda mais simples: " stringexpressionnão é NULL nem vazio" :

stringexpression <> ''

Sobre char(n)

Isto é sobre o tipo de dados char(n), abreviação de: character(n). ( char/ characteré a abreviação de char(1)/ character(1).) Seu uso é desencorajado no Postgres :

Na maioria das situações, textou character varyingdeve ser usado em seu lugar.

Não confundir char(n)com tipos de outro, útil, caráter varchar(n), varchar, textou"char" (com aspas).

Em char(n)uma cadeia vazia não é diferente de qualquer outra cadeia que consiste apenas em espaços. Todos esses itens são dobrados em n espaços, char(n)por definição do tipo. Segue-se logicamente que as expressões acima funcionam char(n)também - exatamente como essas (que não funcionariam para outros tipos de caracteres):

coalesce(stringexpression, '  ') = '  '
coalesce(stringexpression, '') = '       '

Demo

Cadeia vazia é igual a qualquer cadeia de espaços quando convertida para char(n):

SELECT ''::char(5) = ''::char(5)     AS eq1
     , ''::char(5) = '  '::char(5)   AS eq2
     , ''::char(5) = '    '::char(5) AS eq3;

Resultado:

 eq1 | eq2 | eq3
 ----+-----+----
 t   | t   | t

Teste para "cadeia nula ou vazia" com char(n):

SELECT stringexpression 
     , stringexpression = ''                   AS base_test
     , (stringexpression = '')  IS NOT FALSE   AS test1
     , (stringexpression <> '') IS NOT TRUE    AS test2
     , coalesce(stringexpression, '') = ''     AS coalesce1
     , coalesce(stringexpression, '  ') = '  ' AS coalesce2
     , coalesce(stringexpression, '') = '  '   AS coalesce3
FROM  (
   VALUES
     ('foo'::char(5))
   , ('')
   , ('   ')                -- not different from '' in char(n)
   , (NULL)
   ) sub(stringexpression);

Resultado:

expressão de cadeia | base_test | teste1 | teste2 | coalesce1 | coalesce2 | coalesce3
------------------ + ----------- + ------- + ------- + --- -------- + ----------- + -----------
 foo | f f f f f f
                  | t t t t t t
                  | t t t t t t
 null              | null       | t t t t t

Teste para "cadeia nula ou vazia" com text:

SELECT stringexpression 
     , stringexpression = ''                   AS base_test
     , (stringexpression = '')  IS NOT FALSE   AS test1
     , (stringexpression <> '') IS NOT TRUE    AS test2
     , coalesce(stringexpression, '') = ''     AS coalesce1
     , coalesce(stringexpression, '  ') = '  ' AS coalesce2
     , coalesce(stringexpression, '') = '  '   AS coalesce3
FROM  (
   VALUES
     ('foo'::text)
   , ('')
   , ('   ')                -- different from '' in a sane character types
   , (NULL)
   ) sub(stringexpression);

Resultado:

expressão de cadeia | base_test | teste1 | teste2 | coalesce1 | coalesce2 | coalesce3
------------------ + ----------- + ------- + ------- + --- -------- + ----------- + -----------
 foo | f f f f f f
                  | t t t t f f
                  | f f f f f f
 null              | null       | t t t t f

db <> mexe aqui
Old sqlfiddle

Palavras-chave:

Erwin Brandstetter
fonte
2
@a_horse_with_no_name: O OP solicita o best way to check if value is null or empty string. A trim()ligação é (comparativamente) cara - e simplesmente não é necessária. Eu adicionei mais sobre char(n)e "string vazia".
Erwin Brandstetter
1
Você escreveu que qualquer expressão de string contendo apenas espaços é igual a ''. Posso remover a guarnição e usar coalesce(stringexpression,'')=''para verificar. Isso me parece mais legível em comparação com a sua resposta.
Andrus 21/05
1
@ Andrus: Sim, você pode. Eu adicionei isso e um pouco mais à resposta.
Erwin Brandstetter
3
select coalesce(' ', '') = '' retorna falso. Então TRIM () é necessária
Andrus
1
Mas coalesce(' '::char(5), '') = ''não. Em qualquer caso, eu usaria uma das duas principais expressões, que funcionam para qualquer tipo de caractere e são mais rápidas e limpas.
Erwin Brandstetter
46

Para verificar nulos e vazios:

coalesce(string, '') = ''

Para verificar nulos, vazios e espaços (apare a sequência)

coalesce(TRIM(string), '') = ''
sam
fonte
3
Eu gosto dessa simplicidade / clareza desta resposta.
stwr667 3/01
12

A verificação do comprimento da string também funciona e é compacta:

where length(stringexpression) > 0;
yglodt
fonte
Você verificou isso para o caso NULL?
Flinsch 14/01
1
Sim eu fiz. Ele não retorna campos de cadeia vazios nem nulos.
yglodt 14/01
Se você só precisa verificar apenas valores vazios, tente isso -> where length(stringexpression) = 0;. Isso funciona para mim.
Kushan Gunasekera
2

Se houver espaços vazios vazios, provavelmente não há solução melhor. COALESCEé apenas para problemas como o seu.

Świstak35
fonte
1

Algo que eu vi pessoas usando é stringexpression > '' . Pode não ser o mais rápido, mas é um dos mais curtos.

Tentei no MS SQL, bem como no PostgreSQL.

TarasB
fonte
1

outra maneira é

nullif(trim(stringExpression),'') is not null
Mowazzem Hosen
fonte
1
melhor resposta IMHO
Jeff
0

Minha maneira preferida de comparar campos anuláveis ​​é: NULLIF (nullablefield,: ParameterValue) É NULL AND NULLIF (: ParameterValue, nullablefield) É NULL. Isso é complicado, mas é de uso universal, enquanto Coalesce é impossível em alguns casos.

O segundo e inverso uso de NULLIF é porque "NULLIF (campo nulo:: ParameterValue) É NULL" sempre retornará "true" se o primeiro parâmetro for nulo.

Danilo da Silva
fonte
0

Se o banco de dados tiver um grande número de registros, null checkpode levar mais tempo, você pode usar a verificação nula de diferentes maneiras, como: 1) where columnname is null 2) where not exists() 3)WHERE (case when columnname is null then true end)

Ambrish Rajput
fonte
0

Muitas das respostas são a maneira mais curta, não necessariamente a melhor, se a coluna tiver muitos valores nulos. A interrupção das verificações permite que o otimizador avalie a verificação mais rapidamente, pois não precisa trabalhar na outra condição.

(stringexpression IS NOT NULL AND trim(stringexpression) != '')

A comparação de cadeias não precisa ser avaliada, pois a primeira condição é falsa.

John VE
fonte