【问题标题】:SQL CASE checking for two conditions from the same columnSQL CASE 检查同一列中的两个条件
【发布时间】:2015-12-26 11:21:05
【问题描述】:

我目前有一个 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 值?

【问题讨论】:

  • 在第二种和第三种情况下,您应该使用 or 语句而不是 AND。例如声明 (T.PRNAME = 'TECH PEP MEETING DATE' AND T.PRSTATUS = 2) AND (T.PRNAME = 'BRU MEETING DATE' AND T.PRSTATUS != 2) 应该这样写 (T.PRNAME = 'TECH PEP 会议日期'和 T.PRSTATUS = 2) 或 (T.PRNAME = 'BRU 会议日期'和 T.PRSTATUS != 2)
  • @Matthew 现在基于您的错误,问题出在您的 SELECT 子查询中,它返回超过 1 行/记录,请尝试检查您的 SELECT 语句,特别是 WHERE 条件如果为什么它返回超过 1 行。
  • @Matthew 你尝试了第三个WHEN,那里也有选择语句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,请尝试如果也会返回1条记录。
  • 您能否列出查询中使用的所有表及其关系...我可以尝试不同的方法来满足要求!
  • @Matthew Paxman,请修正您的 ELSE 声明。它缺少ROWNUM = 1 条件

标签: sql case multiple-conditions


【解决方案1】:

T.PRNAME = 'TECH PEP 会议日期' 和 T.PRNAME = 'BRU 会议日期'?我认为我们在这里遇到了重叠的情况。

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

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

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)

应该是这样的

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

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

并得到以下结果。

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

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

请单独了解概念,因为我没有您的实际表格。如果您复制整个内容,您几乎会遇到错误。希望这会有所帮助:)

【讨论】:

    【解决方案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
    

    然后进一步简化使用case来使用同一个查询

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

    【讨论】:

    • 我想我应该考虑到 CASE 一旦找到第一个真值就退出的事实(我相信是这样),在这种情况下你是对的。我想我把它复杂化了。
    • @MatthewPaxman 您的子查询在CASE 语句中的重复使得通过眼球检查很难找出错误,结果是您缺少某些条件(ROWNUM = 1)在最后一条语句上。
    【解决方案3】:

    尝试回答 ROWNUM=1 问题,您确定您在 THEN 分支之一中运行吗?您没有在 ELSE 分支中指定 ROWNUM=1。在那里也添加 ROWNUM=1 有帮助吗?

    【讨论】:

      【解决方案4】:

      嗯,

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

      在我看来,经过一些研究,如果您的查询仅返回一行,该 oracle 实际上并没有检查。如果您的语法似乎只允许一行,它会检查。 我不确定。

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

      【讨论】:

        【解决方案5】:

        您的CASE WHEN 条件相互冲突,您在使用AND 时遇到问题。您的第二个和第三个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' 冲突,该条件将永远不会返回TRUE 与您的第三个WHEN 相同

        如果AND 之间的两个条件为真,则使用AND 只会返回真。

        通过阅读您的代码,您的代码的每个 WHEN 中的 AND 似乎需要替换为 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
        

        希望这会有所帮助。

        【讨论】:

        • 嗨,Japz,不幸的是,在这个 CASE 中使用 OR 对我没有帮助,但是在意识到 CASE 在发现 TRUE 条件时会退出之后,我意识到这并不重要。我在帖子下半部分的代码中编辑了 AND 部分。返回多个结果错误是我当前的问题。仍在试图找出原因。
        • @MatthewPaxman 我明白了,好的,现在让我们继续您当前的问题,您说您自己运行SELECT 吗? ,它只返回 1 行? ,如果它也只返回 1 行,您是否尝试过其他 SELECT 语句?
        • 是的,它们都返回一行。有趣的是,如果我将UPPER(T.PRNAME) 更改为仅T.PRNAME,查询将不会返回任何错误,但是它总是会给我 ELSE 结果,尽管我可以看到其中一个 WHEN 子句是正确的。同样,如果我将TECH PEP MEETING DATE 更改为Tech PEP Meeting Date,我会再次收到错误消息。不知道为什么区分大小写会破坏这一点,因为每个 PRNAME 都是独一无二的。
        猜你喜欢
        • 1970-01-01
        • 2022-06-10
        • 1970-01-01
        • 2019-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多