Ejemplo
Tengo una mesa
ID myField
------------
1 someValue
2 NULL
3 someOtherValue
y una expresión booleana T-SQL que puede evaluar como VERDADERO, FALSO o (debido a la lógica ternaria de SQL) DESCONOCIDO:
SELECT * FROM myTable WHERE myField = 'someValue'
-- yields record 1
Si quiero obtener todos los demás registros , no puedo simplemente negar la expresión
SELECT * FROM myTable WHERE NOT (myField = 'someValue')
-- yields only record 3
Sé cómo sucede esto (lógica ternaria) y sé cómo resolver este problema específico.
Sé que puedo usar myField = 'someValue' AND NOT myField IS NULL
y obtengo una expresión "invertible" que nunca produce DESCONOCIDO:
SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)
-- yields records 2 and 3, hooray!
Caso general
Ahora, hablemos del caso general. Digamos que en lugar de myField = 'someValue'
tener una expresión compleja que involucra muchos campos y condiciones, quizás subconsultas:
SELECT * FROM myTable WHERE ...some complex Boolean expression...
¿Hay alguna forma genérica de "invertir" esta expresión? Puntos de bonificación si funciona para subexpresiones:
SELECT * FROM myTable
WHERE ...some expression which stays...
AND ...some expression which I might want to invert...
Necesito admitir SQL Server 2008-2014, pero si hay una solución elegante que requiera una versión más nueva que la de 2008, también estoy interesado en conocerla.
fuente
El primer pensamiento que se me ocurre:
Devoluciones:
Devoluciones:
Esto se basa en la forma en que
EXISTS
siempre devuelve verdadero o falso , nunca desconocido .SELECT 1 WHERE
Desafortunadamente, la necesidad de esto es necesaria, pero podría ser viable para sus requisitos, por ejemplo:Ver EXISTE (Transact-SQL)
Un ejemplo práctico ligeramente más complejo que muestra cómo ya sea
EXISTS
oCASE/IIF
métodos podría aplicarse a invertir predicados individuales:Código:
fuente
Si no le importa reescribir las subexpresiones por adelantado, puede usar
COALESCE
:Usted debe asegurarse de que
'notSomeValue'
es distinta de'someValue'
; preferiblemente, sería un valor completamente ilegal para la columna. (No puede serNULL
, tampoco, por supuesto). Esto es fácil de negar, incluso si tiene una lista larga:Más limpio, más simple y más obvio que
CASE
oIIF
, en mi opinión. El principal inconveniente es que tener un segundo valor que usted sabe no es igual, pero esto solo es realmente un problema si no conoce el valor real por adelantado. En ese caso, puede hacer lo que Hanno Binder sugiere y usarCOALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
(donde'someValue'
realmente estaría parametrizado).COALESCE
está documentado para estar disponible desde SQL Server 2005 en adelante.Tenga en cuenta que jugar con su consulta de esta manera (usando cualquiera de los métodos recomendados aquí) puede dificultar que la base de datos optimice su consulta. Para grandes conjuntos de datos,
IS NULL
es probable que la versión sea más fácil de optimizar.fuente
COALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
debería funcionar para cualquier "someValue" y cualquier dato en la tabla.Existe el operador de conjunto EXCEPT incorporado que, efectivamente, elimina los resultados de una segunda consulta de la primera consulta.
fuente
¿COALESCE está disponible?
fuente
sql-server
, nomysql
opostgresql
.BOOLEAN
tipo y MySQL tiene un tipo (falso)BOOLEAN
que pueden ser parámetros de laCOALESCE()
función. Si la pregunta hubiera sido etiquetada consql-agnostic
osql-standard
, la respuesta estaría bien.