Exemple
J'ai une table
ID myField
------------
1 someValue
2 NULL
3 someOtherValue
et une expression booléenne T-SQL qui peut être évaluée à VRAI, FAUX ou (en raison de la logique ternaire de SQL) INCONNU:
SELECT * FROM myTable WHERE myField = 'someValue'
-- yields record 1
Si je veux obtenir tous les autres enregistrements , je ne peux pas simplement nier l'expression
SELECT * FROM myTable WHERE NOT (myField = 'someValue')
-- yields only record 3
Je sais comment cela se produit (logique ternaire), et je sais comment résoudre ce problème spécifique.
Je sais que je peux simplement utiliser myField = 'someValue' AND NOT myField IS NULL
et j'obtiens une expression "inversible" qui ne donne jamais INCONNU:
SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)
-- yields records 2 and 3, hooray!
Cas général
Maintenant, parlons du cas général. Disons qu'au lieu d' myField = 'someValue'
avoir une expression complexe impliquant de nombreux champs et conditions, peut-être des sous-requêtes:
SELECT * FROM myTable WHERE ...some complex Boolean expression...
Existe-t-il un moyen générique pour "inverser" cette expession? Points bonus si cela fonctionne pour les sous-expressions:
SELECT * FROM myTable
WHERE ...some expression which stays...
AND ...some expression which I might want to invert...
Je dois prendre en charge SQL Server 2008-2014, mais s'il existe une solution élégante nécessitant une version plus récente que 2008, je suis également intéressé d'en entendre parler.
la source
La première pensée qui me vient à l'esprit:
Retour:
Retour:
Cela repose sur la façon dont
EXISTS
retourne toujours vrai ou faux , jamais inconnu . Le besoin deSELECT 1 WHERE
est malheureusement nécessaire, mais il pourrait être réalisable pour votre besoin, par exemple:Voir EXISTS (Transact-SQL)
Un exemple travaillé un peu plus complexe montrant comment les méthodes
EXISTS
ouCASE/IIF
pourraient être appliquées pour inverser les prédicats individuels:Code:
la source
Si cela ne vous dérange pas de réécrire les sous-expressions à l'avance, vous pouvez utiliser
COALESCE
:Vous devez vous assurer que cela
'notSomeValue'
est distinct de'someValue'
; de préférence, ce serait une valeur complètement illégale pour la colonne. (Cela ne peut pas l'être nonNULL
plus, bien sûr.) C'est facile à nier, même si vous avez une longue liste:Plus propre, plus simple et plus évident que
CASE
ouIIF
, à mon avis. L'inconvénient principal est d'avoir une deuxième valeur que vous savez n'est pas égale, mais ce n'est vraiment un problème que si vous ne connaissez pas la valeur réelle à l'avance. Dans ce cas, vous pouvez faire ce que Hanno Binder suggère et utiliserCOALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
(où'someValue'
serait réellement paramétré).COALESCE
est disponible à partir de SQL Server 2005.Sachez que jouer avec votre requête comme celui-ci (en utilisant l'une des méthodes recommandées ici) peut rendre plus difficile pour la base de données l'optimisation de votre requête. Pour les grands ensembles de données, la
IS NULL
version est probablement plus facile à optimiser.la source
COALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
devrait fonctionner pour toute "someValue" et toutes les données de la table.Il y a l' opérateur de jeu EXCEPT intégré qui, en fait, supprime les résultats d'une seconde requête des premiers.
la source
COALESCE est-il disponible?
la source
sql-server
, pasmysql
oupostgresql
.BOOLEAN
type et MySQL a un type (truqué)BOOLEAN
qui peut être des paramètres de laCOALESCE()
fonction. Si la question avait été marquée avecsql-agnostic
ousql-standard
, la réponse serait correcte.