2010-07-28 8 views
4

J'aimerais pouvoir ajouter un champ répondant à la question "Pour une valeur dans cet enregistrement, cette valeur correspond-elle à une condition d'une autre table?". Je pensais essayer un case-when avec un exists, mais Teradata (mes dbms) ne l'aime pas. Des recommandations?SQL: instruction case-when avec "exists"

select foo, 
    (case when exists (select x.foo 
         from somedb x 
         where x.bar > 0) 
    then '1' else '0' end) as MyFlag 

from mydb 
+1

Cela vous donne-t-il une erreur de syntaxe lorsque vous l'exécutez? Quelle est l'erreur? – JNK

+0

Qu'est-ce que "n'aime pas?" Quelle est l'erreur? – Dan

+0

"3771: Expression illégale dans la clause WHEN de CASE expresssion". Voici ce que je fait faire: select t.foo, (cas où 1 = 1 alors fin '1' autre '0') comme lapsedFlag, (cas où existe (sélectionnez cc.date_dt de x. bar cc où cc.foo = t.foo et cc.date_dt entre '2010-05-01' (date) et '2010-07-31' (date) ) puis '1' else '0' end) comme MyFlag de x.bar t – Chris

Répondre

2

je ne pouvais pas trouver une solution qui était facile à lire (touche lorsque vous « re faible d'esprit que je suis), je l'ai fait une union dans une table temporaire:

create multiset table someDb.NiceFlags as 
(
    select t.foo, 
      '1' as myFlag 
    from someDb.pos_txn_mstr t 
    where exists(select x...) 

    union all 

    select t.foo, 
      '0' as myFlag 
    from someDb.pos_txn_mstr t 
    where not exists(select x...) 

) with data primary index(foo) 

Mais maintenant, je ne me sens pas comme un gars dur :(

+0

+1 Je pense que l'UNION ALL est une bonne solution de contournement car l'intention est claire et donc plus facile à corriger lorsque ce 'bug' est corrigé dans une version ultérieure de Teradata (je ne sais pas pourquoi une table temporaire est nécessaire, cependant) – onedaywhen

11

On dirait que vous êtes absent le END pour la déclaration CASE?

select foo, 
    (case when exists (select x.foo 
         from somedb x 
         where x.bar > 0) 
    then '1' else '0' END) as MyFlag 

from mydb 
+1

Bonne réponse. Souvent, ce sont les réponses faciles qui sont nécessaires. – hol

+0

Bonne réponse, mais d'après le commentaire subséquent de Chris à sa question initiale, il semble qu'il ait inclus le END dans l'instruction CASE originale. –

+0

Oui, j'ai la FIN, là. Laissez-moi aller éditer cela ... – Chris

3

Il y a probablement plus d'une solution à cela. Parfois, il existe une relation entre les deux tables. Ensuite, je fais un JOIN et le gère dans la clause WHERE. Je ne connais pas Teradata mais dans Oracle je peux aussi faire quelque chose comme ça.

SELECT foo 
FROM mydb 
WHERE (select count(*) from somedb where x.bar > 0) > 0 

ou peut-être plus comme votre code

select foo, 
    (case when (select count(*) 
         from somedb x 
         where x.bar > 0) > 0 
    then '1' else '0') as MyFlag  
from mydb 

Je sais utiliser la EXISTE que dans la clause WHERE « Je veux seulement que les lignes où les éléments suivants SELECT me donne quelque chose ». Cela n'a de sens que s'il y a un lien entre l'une et l'autre table.

select id,foo from mydb y 
where exists (select x.id from somedb x where x.id = y.id) 
+0

Droite. C'est une sorte de zone grise où j'essaie de mélanger la procédure et la structure dans une union malsaine, mais la structure est en fait "montrez-moi l'information, y compris si l'information passe un test". – Chris

+0

Bien sûr, la solution de secours est d'en avoir deux en deux étapes: une avec le test "if exists" dans le cas où, et mettant littéralement mon drapeau à "1", puis le refaire avec "if not exists", en mettant littéralement le drapeau à "0". Soit dans une table temporaire ou je suppose utiliser un syndicat ... – Chris

+0

@Chris: Je ne suis pas sûr maintenant. Même si je regarde l'autre instruction SQL que vous avez ajoutée comme un commentaire aux questions, je ne suis pas sûr pourquoi mon SQL ne résoudrait pas le problème. Qu'est-ce qui est encore nécessaire? Comme ceci: sélectionnez t.foo, (cas où 1 = 1 puis '1' sinon '0' fin) comme lapsedFlag, (cas où (sélectionnez count (*) de x.bar cc où cc.foo = t. foo et cc.date_dt entre '2010-05-01' (date) et '2010-07-31' (date))> 0 puis '1' else '0' end) comme MyFlag de x.bar – hol

0

Puisque vous n'êtes intéressé que par 1 et 0 en tant que valeurs de drapeau, procédez comme suit:

select foo, 
    coalesce((select max(1) 
      from somedb x 
      where x.bar > 0), 0) as MyFlag 
from mydb 
0

Ne pas utiliser une clause from dans votre existe dans un cas

Case when exists(select x.foo where blahblah>0 then 1 end) from mydb 
Left /inner join somedb x