2015-09-29 5 views
4

J'ai actuellement une instruction CASE qui vérifie si certaines tâches sont terminées ou non, puis renvoie la date de la tâche suivante. Puisque les tâches sont commandées, chaque instruction WHEN devient plus longue, vérifiant chacune des tâches précédentes pour voir si elles sont complètes. Pour une raison quelconque, après la première instruction WHEN, elle saute directement à ELSE (elle devrait répondre aux conditions de la deuxième ou troisième WHEN).SQL CASE vérifiant deux conditions de la même colonne

CASE 
    WHEN T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS != 2 THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'TECH PEP MEETING DATE' AND PRISMILESTONE = 1) 
    WHEN (T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS = 2) AND (T.PRNAME = 'BRU MEETING DATE' AND T.PRSTATUS != 2) THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'BRU MEETING DATE' AND PRISMILESTONE = 1) 
    WHEN (T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS = 2) AND (T.PRNAME = 'BRU MEETING DATE' AND T.PRSTATUS = 2) AND (T.PRNAME = 'TSC MEETING DATE' AND T.PRSTATUS != 2) THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'TSC MEETING DATE' AND PRISMILESTONE = 1) 
    ELSE (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'END OF EVALUATE PHASE' AND PRISMILESTONE = 1) 
END 

Existe-t-il un moyen spécifique pour répondre à ces types de conditions multiples? EDIT: Donc, après quelques commentaires de votre part, je suis d'accord avec l'idée que vous avez seulement besoin d'évaluer une tâche par WHEN parce que l'instruction CASE devrait quitter une fois qu'elle a trouvé sa première déclaration TRUE. Cependant, après avoir mis à jour à:

CASE 
    WHEN UPPER(T.PRNAME) = 'EVALUATE TECH PEP MEETING DATE' AND T.PRSTATUS != 2 THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'TECH PEP MEETING DATE' AND PRISMILESTONE = 1 AND ROWNUM = 1) 
    WHEN UPPER(T.PRNAME) = 'EVALUATE BRU MEETING DATE' AND T.PRSTATUS != 2 THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'BRU MEETING DATE' AND PRISMILESTONE = 1 AND ROWNUM = 1) 
    WHEN UPPER(T.PRNAME) = 'EVALUATE TSC MEETING DATE' AND T.PRSTATUS != 2 THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'TSC MEETING DATE' AND PRISMILESTONE = 1 AND ROWNUM = 1) 
    ELSE (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'END OF EVALUATE PHASE' AND PRISMILESTONE = 1) 
END 

Je reçois maintenant:

ORA-01427: single-row subquery returns more than one row 

Je ne sais pas pourquoi cela est le cas, en particulier après avoir mis ROWNUM = 1 sur la fin pour assurer un seul résultat est retourné.

Lors de l'exécution THEN par lui-même:

SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') 
FROM PRTASK T 
WHERE T.PRPROJECTID = INV_INVESTMENTS.ID 
AND Upper(T.PRNAME) = 'TECH PEP MEETING DATE' 
AND PRISMILESTONE = 1 
AND ROWNUM = 1 

Je reçois un résultat. Si j'ai raison de penser que l'instruction CASE va sortir une fois qu'elle aura trouvé sa première déclaration TRUE, pourquoi trouve-t-on plusieurs lignes?

EDIT 2: Ok - donc j'ai joué avec ça un peu plus (parce que je n'arrive toujours pas à trouver une réponse logique et j'ai fait quelques progrès.) J'ai maintenant changé la façon dont la requête est structurée en suivant:.

SELECT DISTINCT To_Char(T.PRFINISH, 'DD/MM/YY'), 
       T.PRNAME 
FROM PRTASK T 
     LEFT OUTER JOIN INV_INVESTMENTS ON T.PRPROJECTID = INV_INVESTMENTS.ID 
WHERE T.PRNAME = CASE 
        WHEN (T.PRNAME = 'Concept Tech PEP Meeting Date' AND T.PRSTATUS != 2) THEN 'Concept Tech PEP Meeting Date' 
        WHEN (T.PRNAME = 'Concept BRU Meeting Date' AND T.PRSTATUS != 2) THEN 'Concept BRU Meeting Date' 
        WHEN (T.PRNAME = 'End of Concept Phase' AND T.PRSTATUS != 2) THEN 'End of Concept Phase'                             
        WHEN (T.PRNAME = 'Evaluate Tech PEP Meeting Date' AND T.PRSTATUS != 2) THEN 'Evaluate Tech PEP Meeting Date' 
        WHEN (T.PRNAME = 'Evaluate BRU Meeting Date' AND T.PRSTATUS != 2) THEN 'Evaluate BRU Meeting Date' 
        WHEN (T.PRNAME = 'Evaluate TSC Meeting Date' AND T.PRSTATUS != 2) THEN 'Evaluate TSC Meeting Date' 
        WHEN (T.PRNAME = 'End of Evaluate Phase' AND T.PRSTATUS != 2) THEN 'End of Evaluate Phase'      
        WHEN (T.PRNAME = 'End of Analyse Phase' AND T.PRSTATUS != 2) THEN 'End of Analyse Phase' 
        WHEN (T.PRNAME = 'End of Design Phase' AND T.PRSTATUS != 2) THEN 'End of Design Phase' 
        WHEN (T.PRNAME = 'End of Build Phase' AND T.PRSTATUS != 2) THEN 'End of Build Phase' 
        WHEN (T.PRNAME = 'End of Test Phase' AND T.PRSTATUS != 2) THEN 'End of Test Phase' 
        WHEN (T.PRNAME = 'In Service' AND T.PRSTATUS != 2) THEN 'In Service'      
        WHEN (T.PRNAME = 'End of Implement Phase' AND T.PRSTATUS != 2) THEN 'End of Implement Phase' 
        WHEN (T.PRNAME = 'End of Closure Phase' AND T.PRSTATUS != 2) THEN 'End of Closure Phase' 
        ELSE 'In Service' 
        END 
    AND INV_INVESTMENTS.CODE = '007058' 

maintenant, cependant, que je reçois plusieurs déclarations QUAND le retour des valeurs quelqu'un peut-il confirmer si oui ou non les instructions CASE reviennent vraiment que la première valeur TRUE

+0

Vous devez utiliser ou une instruction au lieu de ET dans les deuxième et troisième cas. par exemple. déclaration (T.PRNAME = 'TECH PEP MEETING DATE' ET T.PRSTATUS = 2) ET (T.PRNAME = 'BRU MEETING DATE' et T.PRSTATUS! = 2) devrait être écrit comme ceci (T.PRNAME = 'TECH PEP MEETING DATE' et T.PRSTATUS = 2) OU (T.PRNAME = 'DATE DE RÉUNION DE BRU' ET T.PRSTATUS! = 2) –

+0

@Matthew base sur votre erreur maintenant, le problème est dans votre sous-requête 'SELECT', il retourne plus de 1 ligne/enregistrement, essayez de vérifier votre déclaration' SELECT' spéciailly sur la condition 'WHERE' si pourquoi il renvoie plus de 1 lignes. – Japongskie

+0

@Matthew avez-vous essayé le 3ème 'WHEN', il y a aussi une déclaration select' SELECT TO_CHAR (MAX (T.PRFINISH), 'DD/MM/YY') À PARTIR DE PRTASK T Où T.PRPROJECTID = INV_INVESTMENTS.ID ET Upper (T.PRNAME) = 'TSC MEETING DATE' et PRISMILESTONE = 1 et ROWNUM = 1', essayez de bien vouloir retourner 1 enregistrement. – Japongskie

Répondre

4

le T.PRNAME? = 'TECH PEP MEETING DATE' ET T.PRNAME = 'BRU DATE DE LA RÉUNION'? Je pense que nous avons des conditions qui se chevauchent ici.

Ma haute hypothèse ici est que vous avez 1 table avec beaucoup de tâches avec statut à côté, alors je pense que ce qui devrait arriver ici est quelque chose comme ci-dessous.

D'abord, c'est votre tableau de tâches, j'ai créé quelque chose qui m'est propre.

CREATE TABLE #testtask 
    (
    PRID INT 
    , PRNAME varchar(50) 
    , PRSTATUS INT 
    , PREREQ INT 
) 

    INSERT INTO #testtask VALUES 
    (1,'TECH PEP MEETING DATE',1,0), 
    (2,'BRU MEETING DATE',1,1), 
    (3,'TSC MEETING DATE',1,2) 

pourrait être quelque chose Must comme celui-ci

Ensuite, j'ai créé une jointure gauche sur sa propre table relative à sa mission préalable.

SELECT 
    t1.PRNAME AS [Job] 
    , t1.PRSTATUS AS [JobStatus] 
    , t2.PRNAME AS [PreReqJob] 
    , t2.PRSTATUS AS [PreReqStatus] 
    INTO #taskList 
    FROM #testtask t1 
    LEFT JOIN #testtask t2 
    ON 
    t1.PREREQ = t2.PRID 

et avec le résultat suivant.

enter image description here

avant d'entrer dans ce que je crois est votre script de vérification pour chaque état de la tâche avec les tâches pré-requis.

SELECT 
     CASE 
     WHEN tl.[Job] = 'TECH PEP MEETING DATE' AND tl.[JobStatus] != 2 
      THEN 
       -- do your max select here for 'Tech pep' 
     WHEN tl.[Job] = 'BRU MEETING DATE' AND tl.[JobStatus] != 2 AND tl.[PreReqStatus] = 2 
      THEN 
       -- do your max select here for 'Bru meet' 
     WHEN tl.[Job] = 'TSC MEETING DATE' AND tl.[JobStatus] != 2 AND tl.[PreReqStatus] = 2 
      THEN 
       -- do your max select here for 'Tsc meet' 
     ELSE 
      -- do your default max date 
    END AS [Date] 
    FROM #taskList AS tl 

Veuillez obtenir le concept seul car je n'ai pas vos tables réelles. Vous auriez à peu près une erreur si vous copiez le tout. Espérons que cela aide :)

2

Tout d'abord, corriger votre déclaration de cas pour ce qui lad2025 les points, mais ne pas utiliser de OR et simplifié comme

CASE 
    WHEN T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS != 2 THEN ... 
    WHEN T.PRNAME = 'BRU MEETING DATE' AND T.PRSTATUS != 2 THEN ... 
    WHEN T.PRNAME = 'TSC MEETING DATE' AND T.PRSTATUS != 2 THEN ... 
    ELSE ... 
END 

ensuite de simplifier davantage en utilisant le cas d'utiliser la même requête

Si vous tentez de répondre à la question ROWNUM = 1, êtes-vous sûr de courir dans l'une des branches THEN?
(
    SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') 
    FROM PRTASK T 
    WHERE T.PRPROJECTID = INV_INVESTMENTS.ID 
     AND PRISMILESTONE = 1 
     AND Upper(T.PRNAME) = 
      CASE 
       WHEN T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS != 2 THEN 'TECH PEP MEETING DATE' 
       WHEN T.PRNAME = 'BRU MEETING DATE' AND T.PRSTATUS != 2 THEN 'BRU MEETING DATE' 
       WHEN T.PRNAME = 'TSC MEETING DATE' AND T.PRSTATUS != 2 THEN 'TSC MEETING DATE' 
       ELSE 'END OF EVALUATE PHASE' 
      END 
) 
+0

Je suppose que j'aurais dû considérer le fait que CASE se termine une fois qu'il trouve la première vraie valeur (je crois que c'est le cas), auquel cas vous avez raison. Je l'ai compliqué je pense. –

+0

@MatthewPaxman La duplication de votre sous-requête dans l'instruction 'CASE' rend difficile la détection de l'erreur par vérification oculaire et le résultat est qu'il manque une condition (ROWNUM = 1) sur la dernière instruction. – Eric

2

Vous n'avez pas ROWNUM = 1 spécifié dans la branche ELSE. Cela aide-t-il aussi à ajouter ROWNUM = 1 là?

1

Votre condition CASE WHEN est en conflit les uns avec les autres, vous avez un problème en utilisant AND. Vos 2e et 3e WHEN renverront toujours FALSE, pourquoi? regardez cette ligne ..

WHEN (T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS = 2) 
    AND (T.PRNAME = 'BRU MEETING DATE' AND T.PRSTATUS != 2) 
    THEN... 

Celui T.PRNAME = 'TECH PEP MEETING DATE est conflictuel à la condition AND à côté AND (T.PRNAME = 'BRU MEETING DATE' cette condition ne reviendra TRUE même sur votre 3ème WHEN

En utilisant AND ne retourne vrai, si le deux conditions entre AND est vrai.

En lisant vos codes, il semble que votre AND dans chaque WHEN de votre code doit remplacer par OR pour corriger/supprimer la condition en conflit dans votre colonne T.PRNAME

Ci-dessous le code sont à vous, je l'ai modifié en remplaçant le AND par OR pour corriger votre état.

CASE 
    WHEN T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS != 2 
     THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'TECH PEP MEETING DATE' AND PRISMILESTONE = 1) 
    WHEN (T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS = 2) OR (T.PRNAME = 'BRU MEETING DATE' AND T.PRSTATUS != 2) 
     THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'BRU MEETING DATE' AND PRISMILESTONE = 1) 
    WHEN (T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS = 2) OR (T.PRNAME = 'BRU MEETING DATE' AND T.PRSTATUS = 2) AND (T.PRNAME = 'TSC MEETING DATE' AND T.PRSTATUS != 2) 
     THEN (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'TSC MEETING DATE' AND PRISMILESTONE = 1) 
    ELSE (SELECT TO_CHAR(MAX(T.PRFINISH),'DD/MM/YY') FROM PRTASK T WHERE T.PRPROJECTID = INV_INVESTMENTS.ID AND Upper(T.PRNAME) = 'END OF EVALUATE PHASE' AND PRISMILESTONE = 1) 
END 

Espérons que cela aide.

+0

Hi Japz, malheureusement en utilisant OU ne m'aiderait pas dans ce cas, mais après avoir réalisé que le CAS sortirait quand il a trouvé une condition vraie de toute façon je me suis rendu compte que ce ne serait pas grave. J'ai édité la partie ET du code dans la moitié inférieure de mon message. Le retour de plus d'une erreur de résultat est mon problème actuel. Je cherche toujours à savoir pourquoi. –

+0

@MatthewPaxman Je vois, ok passons à votre problème actuel maintenant, vous avez dit que vous exécutez le 'SELECT' par lui-même? , et il retourne seulement 1 ligne? , avez-vous essayé l'autre instruction 'SELECT' s'il y a aussi une seule ligne? – Japongskie

+0

Oui, ils retournent tous une rangée. Fait intéressant, si je change 'UPPER (T.PRNAME)' en juste 'T.PRNAME' la requête ne renverra aucune erreur, cependant elle me donnera toujours le résultat ELSE, malgré le fait que je puisse voir que l'une des clauses WHEN sont vrai. De même, si je change «TECH PEP MEETING DATE» en «Tech PEP Meeting Date», j'obtiens à nouveau l'erreur. Je ne sais pas pourquoi la sensibilité à la casse brise cela car chacun de ces PRNAME est unique. –

2

Uhm,

j'ai essayé de sqlfiddle votre question, mais il y a beaucoup aux tables inconnues utilisées. Pour obtenir une meilleure aide, essayez de construire un sqlfiddle que vos assistants peuvent utiliser.

Après quelques recherches il me semble, que l'oracle ne vérifie pas en fait, si votre requête renvoie seulement une ligne. il vérifie, si votre syntaxe semble ne permettre qu'une seule ligne. Je ne suis pas sûr à ce sujet. Essayez d'utiliser un max (x) autour de tous vos champs de sous-requête-singuliers singuliers et jetez un oeil, si oracle l'accepte. Si vous n'obtenez qu'une seule ligne, max() ne change pas votre valeur, alors utilisez-la.