SQL CASE检查同一列中的两个条件

时间:2015-09-29 05:18:03

标签: sql case multiple-conditions

我目前有一个CASE语句,用于检查某些任务是否已完成,然后返回下一个任务的日期。由于任务是有序的,因此每个WHEN语句变得更长,检查先前的每个任务以查看它们是否完整。出于某种原因,在第一个WHEN声明之后,它直接跳到ELSE(它应该满足第二个或第三个WHEN的条件)。

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

您需要一种特定的方式来解决这些类型的多个WHEN条件吗?

编辑:所以在你们的一些反馈之后,我同意你只需要评估每个WHEN的一个任务,因为CASE语句一旦找到第一个TRUE语句就应该退出。但是,已将其更新为:

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

我现在得到:

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

不确定为什么会出现这种情况,特别是在最后添加ROWNUM = 1以确保只返回一个结果。

单独运行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

我得到一个结果。如果我认为CASE语句一旦找到第一个TRUE语句就会退出,为什么会发现多行?

编辑2:好的 - 所以我一直在玩这个(因为我仍然无法找到合乎逻辑的答案,我已经取得了一些进展。我现在已经改变了查询结构的方式以下内容:

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'

但是,现在,我正在获取多个返回值的WHEN语句。任何人都可以确认CASE语句是否真的只返回第一个TRUE值吗?

5 个答案:

答案 0 :(得分:4)

T.PRNAME =' TECH PEP会议日期' AND T.PRNAME =' BRU会议日期'?我认为我们在这里有重叠的条件。

我在这里的高度假设是你有一张桌子,其中有许多任务,旁边有状态,那么我认为这里应该发生的事情如下所示。

首先是你的任务表,我自己创造了一些东西。

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)

必须是这样的

enter image description here

然后,我在自己的表上创建了一个与其先决任务相关的左连接。

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

以及以下结果。

enter image description here

在进入我认为是你的脚本检查每个任务状态与先决条件任务之前。

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

请单独了解这个概念,因为我没有你的实际表格。如果你复制整件事,你几乎会有错误。希望这有助于:)

答案 1 :(得分:2)

首先,针对lad2025指出的内容修复您的案例陈述,但不使用任何OR,并简化为

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

然后进一步简化使用案例来使用相同的查询

(
    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
)

答案 2 :(得分:2)

尝试回答ROWNUM = 1问题,你确定你在其中一个分支机构中运行吗?您没有在ELSE分支中指定ROWNUM = 1。在那里添加ROWNUM = 1会有帮助吗?

答案 3 :(得分:2)

嗯,

我试图找到你的问题,但是使用了很多未知的表。 为了获得更好的帮助,请尝试构建一些助手可以使用的sqlfiddle。

经过一些研究后,在我看来,如果你的查询只返回一行,那么oracle实际上并没有检查。它检查,如果你的语法似乎只允许一行。 我不确定这一点。

尝试在所有单个子查询返回字段周围使用max(x),如果oracle接受这个,请看一下。如果你真的只得到一行,那么max()不会改变你的值,所以要使用它。

答案 4 :(得分:1)

您的CASE WHEN条件相互冲突,使用AND时遇到问题。您的第2和第3 WHEN将始终返回FALSE,为什么?看看这一行..

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

这一个T.PRNAME = 'TECH PEP MEETING DATE与其旁边的AND条件AND (T.PRNAME = 'BRU MEETING DATE'发生冲突,该条件永远不会在您的第3个TRUE WHEN >

如果AND之间的两个条件为真,则使用AND将仅返回true。

通过阅读您的代码,您的AND代码中的WHEN似乎需要由OR替换,以更正/删除列T.PRNAME中的冲突条件

以下代码是您的,我修改后将AND替换为OR来纠正您的情况。

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

希望这有帮助。