如何在PL / SQL函数的select语句中有多个CASE?

时间:2018-05-04 17:19:39

标签: sql oracle plsql

我试图编写一个包含2个case语句的函数。对于背景,用户可以拥有A,B或A和B两者(但在不同的行上,这就是为什么我不能使用单个案例陈述,除非我使用LISTAGG,我被告知不要做到这一点。

示例数据:

User State 
1       A 
1       B 
2       A 
3       B

SQL

CREATE OR REPLACE Function F_Calc_State(code Varchar2, id Number, time varchar2) Return Varchar2 AS

    Calc_State(10) := null;

    l_A varchar2(10) := null;
    l_B varchar2(10) := null;

BEGIN

    SELECT CASE WHEN state = 'A' THEN 'A'
                ELSE null 
           END into l_A,   
           CASE WHEN state = 'B' THEN 'B'
                ELSE null 
           END into l_B
      FROM TABLE1
     WHERE state in ('A', 'B')
       AND TABLE1_CODE = code
       AND TABLE1_ID   = id
       AND TABLE1_TIME = time;

    CASE WHEN l_A = 'A' and l_B = 'B' then 'AB'
         WHEN l_A = 'A' THEN 'A'
         WHEN 1_B = 'B' THEN 'B'
         ELSE stafford_recip_ind :='NEITHER';
    END CASE;

    RETURN Calc_State;

EXCEPTION
    WHEN NO_DATA_FOUND THEN 
        RETURN 'NO DATA';
    WHEN OTHERS THEN 
        RETURN SQLERRM ;
END  F_Calc_State;`

对于想要的结果,当我输入用户1时,我想要返回AB,对于用户2 = A,用户3 = B.我也尝试过两个不同的select语句块但是无法得到它也可以工作,它会因某种原因而遇到异常处理程序。谢谢!

3 个答案:

答案 0 :(得分:2)

如果没有找到数据,以下代码将返回NULL

CREATE OR REPLACE Function F_Calc_State (
    in_code Varchar2,
    in_id Number,
    in_time varchar2  -- "time" as a string is highly suspicious
) Return Varchar2 
AS
    v_ab varchar2(10) := null;
BEGIN

    SELECT MAX(CASE WHEN t1.state = 'A' THEN 'A' END) ||
           MAX(CASE WHEN t1.state = 'B' THEN 'B' END)
    INTO v_AB
    FROM  TABLE1 t1
    WHERE t1.state in ('A', 'B') AND
          t1.TABLE1_CODE = in_code AND
          t1.TABLE1_ID = in_id AND
          t1.TABLE1_TIME = in_time;    
    RETURN(v_ab);
END;  -- F_Calc_State

但是,如果没有找到数据,则不会返回错误。

CREATE OR REPLACE Function F_Calc_State (
    in_code Varchar2,
    in_id Number,
    in_time varchar2  -- "time" as a string is highly suspicious
) Return Varchar2 
AS
    v_ab varchar2(10) := null;
BEGIN

    SELECT MAX(CASE WHEN t1.state = 'A' THEN 'A' END) ||
           MAX(CASE WHEN t1.state = 'B' THEN 'B' END)
    INTO v_AB
    FROM  TABLE1 t1
    WHERE t1.state in ('A', 'B') AND
          t1.TABLE1_CODE = in_code AND
          t1.TABLE1_ID = in_id AND
          t1.TABLE1_TIME = in_time;  
    GROUP BY t1.TABLE1_CODE;  -- this will return no rows if there are no matches

    RETURN(v_ab);

    EXCEPTION
        WHEN NO_DATA_FOUND THEN RETURN 'NO DATA';
        WHEN OTHERS THEN RETURN SQLERRM ;

END;  -- F_Calc_State

答案 1 :(得分:1)

使用下面的代码,现在您将只获得一行结果。

SELECT MAX(CASE WHEN state = 'A' THEN 'A'
                ELSE null END),    
       MAX(CASE WHEN state = 'B' THEN 'B'
                ELSE null END)
INTO l_A, l_B
FROM TABLE1
 WHERE state in ('A', 'B')
   AND TABLE1_CODE = code
   AND TABLE1_ID   = id
   AND TABLE1_TIME = time;

答案 2 :(得分:0)

一个非常简单的方法可能是这样的: 目前尚不清楚是否要检查是否存在记录,如在异常块中返回“NO DATA”,而在您的case语句中,您的值为“NEITHER”..无论如何,您可以相应地调整此值:

CREATE OR REPLACE Function F_Calc_State( code varchar2
                                       , id number
                                       , time varchar2
                                       ) return varchar2 
as
  l_count_a number;
  l_count_b number;
  l_result varchar2(10);

begin

  select count(*)
    into l_count_a
    from table1
   where state = 'A'
     and table1_code = id
     and table1_time = time;

  select count(*)
    into l_count_b
    from table1
   where state = 'B'
     and table1_code = id
     and table1_time = time;

  if    l_count_a = 0 and l_count_b = 0 then l_result := 'NEITHER'; 
  elsif l_count_a > 0 and l_count_b = 0 then l_result := 'A';
  elsif l_count_a = 0 and l_count_b > 0 then l_result := 'B';
  elsif l_count_a > 0 and l_count_b > 0 then l_result := 'AB';
  else  l_result := '';
  end if;

  return l_result;
end F_Calc_State;