select 基于 oracle 中存在的行数的单行

select single row based on count of rows present oracle

我使用查询得到了以下 table,现在我想根据下面解释的条件获取单个记录并将其分配给两个变量,即声明的 v_dte_meetingv_status_meeting在我的存储过程中,

 Dte_Meeting| Ststus_Meeting
########################
15-Oct-14   | Due    
30-Oct-14   | Due
15-Dec-14   | Init
30-Dec-14   | Init
30-Nov-15   | Approved

我想根据以下条件为这些变量赋值:

  1. 如果一个或多个记录以 Status_Meeting 作为 'Due' 则分配 v_dte_meeting 具有 'Due' 状态的最大日期并分配 v_status_meeting 值'Due'
  2. 如果上述条件不成立,则检查是否有单个或多个记录以 Ststus_Meeting 作为 'Init' 如果是,则分配 v_dte_meeting 最大日期 'Init' 状态并为 v_status_meeting 赋值 'Init'
  3. 如果两个条件都失败,则为两个变量分配 NULL 值

请帮助我在 Oracle 中以最佳方式做到这一点

一种方法使用聚合:

select (case when sum(case when status_meeting = 'Due' then 1 else 0 end) > 0
             then max(case when status_meeting = 'Due' dte_meeting end)
             when sum(case when status_meeting = 'Init' then 1 else 0 end) > 0
             then max(case when status_meeting = 'Init' then dte_meeting end)
        end),  
       (case when sum(case when status_meeting = 'Due' then 1 else 0 end) > 0
             then'Due'
             when sum(case when status_meeting = 'Init' then 1 else 0 end) > 0
             then 'Init'
        end)
into v_dte_meeting, v_status_meeting
from t;

但是,我认为更简单的版本只使用 order by:

select max(dte_meeting), max(status_meeting)
into v_dte_meeting, v_status_meeting
from (select t.*
      from t
      where status_meeting in ('Due', 'Init')
      order by (case when status_meeting = 'Due' then 1
                     when status_meeting = 'Init' then 2
                end)
     ) t
where rownum = 1;

max()只是为了保证正好返回一行。

希望这对您有所帮助。我只展示 SELECT 语句(我没有创建变量,所以我没有选择 INTO,但这不是你的难点,你知道怎么做。)我使用子查询分解(WITH 子句),我相信只能在 >= 11 的版本中使用,否则你可以重写以将子查询放在它们所属的位置。

注意rank()的使用;在 Gordon 的解决方案中,他将在所有行中获取 max(dte),而不仅仅是状态 = 'Due' 的行,因此它不可能像他写的那么简单。编辑:我也看不到他在哪里选择 NULL,如果 'Due' 和 'Init' 都不存在则为 NULL。 (抱歉辱骂,这应该是对他的回答的评论,我没有权限。)

WITH t (Date_Meeting, Status_Meeting) AS
   (
      SELECT TO_DATE('15-OCT-14', 'DD-MON-YY'), 'Due' FROM dual UNION ALL
      SELECT TO_DATE('30-OCT-14', 'DD-MON-YY'), 'Due' FROM dual UNION ALL
      SELECT TO_DATE('15-DEC-14', 'DD-MON-YY'), 'Init' FROM dual UNION ALL
      SELECT TO_DATE('30-DEC-14', 'DD-MON-YY'), 'Init' FROM dual UNION ALL
      SELECT TO_DATE('15-NOV-15', 'DD-MON-YY'), 'Approved' FROM dual
   ),
     s (Date_Meeting, Status_Meeting) AS
   (
      SELECT Date_Meeting, Status_Meeting FROM t 
            WHERE Status_Meeting = 'Due' OR Status_Meeting = 'Init'
      UNION ALL SELECT NULL, NULL FROM dual  -- To ensure you have the nulls if needed
   ),
    r (Date_Meeting, Status_Meeting, rk) AS
   (
      SELECT Date_Meeting, Status_Meeting, 
             RANK() OVER (ORDER BY DECODE(Status_Meeting, 'Due', 0, 'Init', 1, 2), 
                          Date_Meeting DESC)  -- make sure you understand this
      FROM s
   )
SELECT Date_Meeting, Status_Meeting FROM r WHERE rk = 1
/

结果:

DATE_MEET STATUS_M
--------- --------
30-OCT-14 Due

1 row selected.