简体   繁体   English

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

[英]SQL CASE checking for two conditions from the same column

I currently have a CASE statement that checks to see whether certain tasks are completed or not, and then returns the date of the next task. 我目前有一个CASE语句,用于检查某些任务是否已完成,然后返回下一个任务的日期。 Since the tasks are ordered, each WHEN statement becomes longer, checking each of the previous tasks to see if they're complete. 由于任务是有序的,因此每个WHEN语句变得更长,检查先前的每个任务以查看它们是否完整。 For some reason, after the first WHEN statement, it's skipping straight to ELSE (it should be meeting the conditions of the second or third 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

Is there a specific way you need to address these types of multiple WHEN conditions? 有没有特定的方法来解决这些类型的多个WHEN条件?

EDIT: So after some feedback from you guys I agree with the idea that you only need to evaluate one task per WHEN because the CASE statement should exit once it finds its first TRUE statement. 编辑:所以在你们的一些反馈之后,我同意你只需要评估每个WHEN的一个任务,因为CASE语句一旦找到第一个TRUE语句就应该退出。 However, having updated it to: 但是,将其更新为:

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

I am now getting: 我现在得到:

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

Not sure why this is the case, especially having put ROWNUM = 1 on the end to ensure only one result is returned. 不知道为什么会这样,特别是在结尾放置ROWNUM = 1以确保只返回一个结果。

When running the THEN by itself: 当自己运行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

I'm getting one result. 我得到了一个结果。 If I'm right in thinking that the CASE statement will exit once it finds its first TRUE statement, why is this finding multiple rows? 如果我认为CASE语句一旦找到第一个TRUE语句就会退出,为什么这会发现多行?

EDIT 2: Ok - so I've been playing around with this some more (because I still cannot find a logical answer and I've made some headway. I have now changed the way the query is structured to the following: 编辑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'

Now, however, I'm getting multiple WHEN statements returning values. 但是,现在我得到多个返回值的WHEN语句。 Can anyone confirm whether or not CASE statements truly only return the first TRUE value? 任何人都可以确认CASE语句是否真的只返回第一个TRUE值?

The T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRNAME = 'BRU MEETING DATE'? T.PRNAME ='TECH PEP会议日'和T.PRNAME ='BRU会议日期'? I think we're having an overlapping conditions here. 我想我们这里有重叠的条件。

My high assumption here is that you have 1 table with many task with status beside, then I think what should happen here is something as below. 我在这里的高度假设是你有1个表,其中有许多任务与状态相邻,那么我认为这里应该发生的事情如下所示。

First is your table of tasks, I created something my own. 首先是你的任务表,我创造了自己的东西。

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)

Must might be something like this 必须是这样的

在此输入图像描述

Then, I created a left join on its own table related to its pre-requisite task. 然后,我在自己的表上创建了一个与其先决条件任务相关的左连接。

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

and with this following result. 并得到以下结果。

在此输入图像描述

before getting into what I believe is your script checking for each task state with pre-requisite tasks. 在进入我认为你的脚本检查每个任务状态与先决条件任务之前。

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

Please get the concept alone as I do not have your actual tables. 因为我没有你的实际表,所以请单独理解这个概念。 You would pretty much have an error if you copy the whole thing. 如果你复制整件事,你几乎会有错误。 Hopefully this helps :) 希望这有助于:)

First, fix your case statement for what lad2025 points out, but not using any OR , and simplified as 首先,修复你的case语句,找出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

Then further simplify using the case to use the same query 然后进一步简化使用案例来使用相同的查询

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

Trying to answer the ROWNUM=1 question, are you sure you are running in one of the THEN branches? 试图回答ROWNUM = 1问题,你确定你在其中一个分支机构中运行吗? You do not have ROWNUM=1 specified in the ELSE branch. 您没有在ELSE分支中指定ROWNUM = 1。 Does it help to also add ROWNUM=1 there? 在那里添加ROWNUM = 1有帮助吗?

uhm, 嗯,

i tried to sqlfiddle your question, but there is to much unknown tables used. 我试图找到你的问题,但是使用了很多未知的表。 To get better help, try to build some sqlfiddle your helpers can use. 为了获得更好的帮助,请尝试构建一些助手可以使用的sqlfiddle。

After some research it seems to me, that oracle does not in fact checks, if your query returns only one row. 经过一些研究,在我看来,如果你的查询只返回一行,那么oracle实际上并没有检查。 it checks, if your syntax seems to allow only one row. 它检查,如果你的语法似乎只允许一行。 I'm not sure about this. 我不确定这个。

Try using a max(x) around all your singular subquery-return-fields and hae a look, if oracle is accepting this. 如果oracle接受这个,请尝试在所有单个子查询返回字段周围使用max(x)。 If you really get only one row, a max() does not change your value, so use it. 如果你真的只有一行,max()不会改变你的值,所以使用它。

Your CASE WHEN condition conflicts to each other, you have problem in using AND . 您的CASE WHEN条件相互冲突,您在使用AND遇到问题。 Your 2nd and 3rd WHEN will always return FALSE , why ? 你的第二个和第三WHEN总是会返回FALSE ,为什么呢? look at this line.. 看看这一行..

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

This one T.PRNAME = 'TECH PEP MEETING DATE is conflicted to the AND condition next to it AND (T.PRNAME = 'BRU MEETING DATE' that condition will never return TRUE same on your 3rd WHEN 这一个T.PRNAME = 'TECH PEP MEETING DATE与其旁边的AND条件冲突AND (T.PRNAME = 'BRU MEETING DATE' ,该条件永远不会在您的第3个WHEN上返回TRUE

Using AND will only return true, if the two condition between AND is true. 使用AND只会返回true,如果两者之间的条件AND是真实的。

By reading your codes, it seems your AND in each WHEN of your code needs to replace by OR to correct/remove the conflicting condition in your column T.PRNAME 通过阅读您的代码,您的代码的每个WHENAND似乎需要由OR替换,以更正/删除列T.PRNAME中的冲突条件

Below code are yours, i modified it replacing the AND by OR to correct your condition. 下面的代码是你的,我修改它取代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

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM