É uma maneira postgres de combinar IS DISTINCT FROM
ou ANY
alguma outra maneira legal de obter o mesmo resultado?
select count(*)
from (select 'A' foo union all select 'Z' union all select null) z
where foo <> any(array[null, 'A']);
count
-------
1
(1 row)
select count(*)
from (select 'A' foo union all select 'Z' union all select null) z
where foo is distinct from any(array[null, 'A']);
ERROR: syntax error at or near "any"
LINE 3: where foo is distinct from any(array[null, 'A']);
^
Olhando para ele como um problema de gramática,
ANY
é definido como (em comparações de linha e matriz ):Mas
is distinct from
não é um operador, é uma "construção" como nos é dito em Operadores de Comparação :Como o PostgreSQL possui operadores definidos pelo usuário, podemos definir uma combinação operador/função para esse propósito:
Então pode preceder
ANY
:Operador
Isso é baseado no operador inteligente de @Daniel .
Enquanto estiver nisso, crie a combinação função/operador usando tipos polimórficos . Então funciona para qualquer tipo - assim como a construção.
E faça a função
IMMUTABLE
.Uma pesquisa rápida com o symbolhound não deu certo , então o operador
<!>
não parece estar em uso em nenhum dos módulos.Se você for usar muito esse operador, poderá desenvolvê-lo um pouco mais para ajudar o planejador de consultas ( como losthorse sugerido em um comentário ). Para começar, você pode adicionar as cláusulas
COMMUTATOR
e para auxiliar o otimizador de consulta.NEGATOR
SubstituaCREATE OPERATOR
de cima por isto:E adicione:
Mas as cláusulas adicionais não ajudarão no caso de uso em questão e os índices simples ainda não serão usados. É muito mais sofisticado conseguir isso. (Não tentei.) Leia o capítulo "Informações de otimização do operador" no manual para obter detalhes.
Caso de teste
O caso de teste na questão só pode ser bem-sucedido se todos os valores na matriz forem idênticos. Para o array na pergunta (
'{null,A}'::text[]
) o resultado é sempre TRUE. Isso é pretendido? Adicionei outro teste para "IS DISTINCT FROM ALL":Alternativa com operadores padrão
quase pode ser traduzido para
foo = ALL (test_arr)
rendimentos ...TRUE
.. se todos os elementos sãofoo
FALSE
.. se algumNOT NULL
elemento é<> foo
NULL
.. se pelo menos um elementoIS NULL
e nenhum elemento é<> foo
Portanto, o caso do canto restante é onde
-
foo IS NULL
- e
test_arr
consiste em nada além deNULL
elementos.Se qualquer um deles puder ser descartado, estamos perdidos. Portanto, use o teste simples se
- a coluna estiver definida
NOT NULL
.- ou você sabe que a matriz nunca é toda NULL.
Caso contrário, teste adicionalmente:
Onde
'A'
e'B'
pode ser qualquer valor distinto. Explicação e alternativas nesta questão relacionada em SO:É array todos os NULLs no PostgreSQL
Novamente, se você conhece algum valor que não pode existir em
test_arr
, por exemplo, a string vazia''
, ainda pode simplificar:Aqui está uma matriz de teste completa para verificar todas as combinações:
Isso é um pouco mais detalhado do que a solução de Andriy
EXCEPT
, mas é substancialmente mais rápido.Talvez assim :
Observe que não apenas o
null
in no "array", mas também onull
inz
está sendo comparado dessa maneira.