Utilisation de CASE WHEN dans la condition where

Je me demandais si quelqu'un pouvait m'aider à écrire du code pour la logique suivante.

Nous avons une table

---------------- id, lang, letter ---------------- 1 1 E 1 1 E 1 1 E 1 1 E 2 2 F 

Problème:

Je dois sélectionner TOUTES les lignes pour lesquelles la condition suivante échoue:

  • id = lang (ie soit 1 ou 2)
  • lang = 1 quand letter = 'e' OU lang = 2 quand letter = 2

Je sais que je peux le coder en dur. Aussi, je voudrais le faire dans une seule requête.

S'il vous plaît aider

Je pense que c'est ce que vous voulez exclure des loggings répondant à ces critères:

 create table #t ( id int, lang int, letter varchar(1) ) insert into #t values (1, 1, 'E') insert into #t values (1, 1, 'E') insert into #t values (1, 1, 'E') insert into #t values (1, 1, 'E') insert into #t values (2, 2, 'F') insert into #t values (1, 1, 'G') insert into #t values (1, 1, 'H') insert into #t values (1, 1, 'I') insert into #t values (1, 1, 'J') insert into #t values (2, 2, '2') SELECT * FROM #t WHERE NOT ( id = lang AND ( ( lang = 1 AND letter = 'E' ) OR ( lang = 2 AND letter = '2' ) ) ) drop table #t 

pour get les loggings avec cela, il suffit de retirer le NOT it:

 SELECT * FROM #t WHERE ( id = lang AND ( ( lang = 1 AND letter = 'E' ) OR ( lang = 2 AND letter = '2' ) ) ) 
 WHERE NOT ( id = lang AND ( (lang = 1 AND letter = 'e') OR (lang = 2 AND letter = '2') ) ) 
 select * from table where id <> lang and (lang<>1 and letter <> 'e' or lang<>2 and letter <> '2') 

En supposant que vous voulez dire que vous voulez toutes datatables où ces deux conditions sont fausses.

L'idée ici est qu'il y a trois règles métier qui peuvent être implémentées sous la forme de trois contraintes de tuple distinctes (c'est-à-dire non fausses pour chaque ligne de la table):

  1. id et lang doivent être égaux (en posant la question, pourquoi ne pas en faire une colonne calculée?).

  2. Si la letter est 'E' alors lang doit être 1 (je suppose qu'il y a une faute de frappe dans votre question où vous avez dit 'e' au lieu de 'E' ).

  3. Si la letter est 'F' alors lang doit être 2 (je suppose qu'il y a une faute de frappe dans votre question où vous avez dit 2 au lieu de 'F' ).

Les contraintes "n'ont rien à dire" à propos d'autres données (par exemple, quand la letter est 'X' ) et permettent que cela passe.

Les trois contraintes de tuple peuvent être écrites sous forme normale conjonctive en tant que requête de validation de contrainte:

 SELECT * FROM T WHERE id = lang AND ( letter <> 'E' OR lang = 1 ) AND ( letter <> 'F' OR lang = 2 ) 

Les données qui violent les contraintes peuvent être simplement montrées (en pseudo-algèbre relationnelle) comme:

 T MINUS (constraint validation query) 

En SQL:

 SELECT * FROM T EXCEPT SELECT * FROM T WHERE id = lang AND ( letter <> 'E' OR lang = 1 ) AND ( letter <> 'F' OR lang = 2 ) 

Il est bon de pouvoir réécrire les prédicats dans le cas où la requête de son choix fonctionne comme de la colle sur son SGBD préféré! Ce qui précède peut être réécrit comme par exemple

 SELECT * FROM T WHERE NOT ( id = lang AND ( letter <> 'E' OR lang = 1 ) AND ( letter <> 'F' OR lang = 2 ) ) 

Appliquer les lois de réécriture (De Morgan et double négatif)

 SELECT * FROM T WHERE id <> lang OR ( letter = 'E' AND lang <> 1 ) OR ( letter = 'F' AND lang <> 2 ) 

Logiquement parlant, cela devrait être mieux pour l'optimiseur car pour que cela soit une contradiction, chaque membre disjoint doit être faux (en d'autres termes, il faut seulement une clause OR'ed pour que datatables soient considérées comme 'mauvaises') . En pratique (en théorie?), L'optimiseur devrait pouvoir effectuer de telles réécritures de toute façon!

ps Les zéros sont mauvais pour la logique – évitez-les!


Voici mon code de test avec des exemples de données:

 WITH Nums AS ( SELECT * FROM ( VALUES (0), (1), (2) ) AS T (c) ), Chars AS ( SELECT * FROM ( VALUES ('E'), ('F'), ('X') ) AS T (c) ), T AS ( SELECT N1.c AS id, N2.c AS lang, C1.c AS letter FROM Nums AS N1, Nums AS N2, Chars AS C1 ) SELECT * FROM T EXCEPT SELECT * FROM T WHERE id = lang AND ( letter <> 'E' OR lang = 1 ) AND ( letter <> 'F' OR lang = 2 );