Operador
Esto se basa en el operador inteligente de @Daniel .
Mientras lo hace, cree el combo de función / operador utilizando tipos polimórficos . Entonces funciona para cualquier tipo, al igual que la construcción.
Y hacer la función IMMUTABLE
.
CREATE FUNCTION is_distinct_from(anyelement, anyelement)
RETURNS bool LANGUAGE sql IMMUTABLE AS
'SELECT $1 IS DISTINCT FROM $2';
CREATE OPERATOR <!> (
PROCEDURE = is_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
);
Una búsqueda rápida con Symbolhound quedó vacía, por lo que el operador <!>
no parece estar en uso en ninguno de los módulos.
Si va a utilizar mucho este operador, puede desarrollarlo un poco más para ayudar al planificador de consultas ( como los sugeridos en un comentario ). Para empezar, puede agregar las cláusulas COMMUTATOR
y NEGATOR
para ayudar al optimizador de consultas. Reemplazar CREATE OPERATOR
desde arriba con esto:
CREATE OPERATOR <!> (
PROCEDURE = is_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
, COMMUTATOR = <!>
, NEGATOR = =!=
);
Y añadir:
CREATE FUNCTION is_not_distinct_from(anyelement, anyelement)
RETURNS bool LANGUAGE sql IMMUTABLE AS
'SELECT $1 IS NOT DISTINCT FROM $2';
CREATE OPERATOR =!= (
PROCEDURE = is_not_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
, COMMUTATOR = =!=
, NEGATOR = <!>
);
Pero las cláusulas adicionales no ayudarán con el caso de uso en cuestión y los índices simples todavía no se utilizarán. Es mucho más sofisticado lograr eso. (No lo he intentado). Lea el capítulo "Información de optimización del operador" en el manual para obtener más detalles.
Caso de prueba
El caso de prueba en la pregunta solo puede tener éxito si todos los valores de la matriz son idénticos. Para la matriz en la pregunta ( '{null,A}'::text[]
) el resultado es siempre VERDADERO. ¿Es eso intencionado? Agregué otra prueba para "ES DISTINTO DE TODO":
SELECT foo
, foo <!> ANY ('{null,A}'::text[]) AS chk_any
, foo <!> ALL ('{null,A}'::text[]) AS chk_all
FROM (
VALUES ('A'),('Z'),(NULL)
) z(foo)
foo | chk_any | chk_all
-----+---------+---------
A | t | f
Z | t | t
| t | f
Alternativa con operadores estándar
foo IS DISTINCT FROM ANY (test_arr) -- illegal syntax
puede casi ser traducido a
foo = ALL (test_arr) IS NOT TRUE
foo = ALL (test_arr)
rinde ...
TRUE
.. si todos los elementos son foo
FALSE
.. si algún NOT NULL
elemento es <> foo
NULL
.. si al menos un elemento IS NULL
y ningún elemento es<> foo
Entonces, el caso de la esquina restante es donde
- foo IS NULL
- y test_arr
consiste en nada más que NULL
elementos.
Si cualquiera de los dos puede descartarse, ya hemos terminado. Por lo tanto, use la prueba simple if
- la columna está definida NOT NULL
.
- o que sabe la matriz no es todos los valores NULL.
De lo contrario, prueba adicionalmente:
AND ('A' = ALL(test_arr) IS NOT NULL OR
'B' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL)
Donde 'A'
y 'B'
puede ser cualquier valor distinto. Explicación y alternativas bajo esta pregunta relacionada sobre SO:
¿Es la matriz todos NULL en PostgreSQL
Nuevamente, si conoce algún valor que no puede existir test_arr
, por ejemplo, la cadena vacía ''
, aún puede simplificar:
AND ('' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL)
Aquí hay una matriz de prueba completa para verificar todas las combinaciones:
SELECT foo, test_arr
, foo = ALL(test_arr) IS NOT TRUE AS test_simple
, foo = ALL(test_arr) IS NOT TRUE
AND ('A' = ALL(test_arr) IS NOT NULL OR
'B' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL) AS test_sure
FROM (
VALUES ('A'),('Z'),(NULL)
) v(foo)
CROSS JOIN (
VALUES ('{null,A}'::text[]),('{A,A}'),('{null,null}')
) t(test_arr)
foo | test_arr | test_simple | test_sure
-----+-------------+-------------+-----------
A | {NULL,A} | t | t
A | {A,A} | f | f -- only TRUE case
A | {NULL,NULL} | t | t
Z | {NULL,A} | t | t
Z | {A,A} | t | t
Z | {NULL,NULL} | t | t
| {NULL,A} | t | t
| {A,A} | t | t
| {NULL,NULL} | t | f -- special case
Esto es un poco más detallado que la EXCEPT
solución de Andriy , pero es sustancialmente más rápido.