【问题标题】:select single row based on count of rows present oracle根据存在的行数选择单行 oracle
【发布时间】:2016-07-14 02:28:51
【问题描述】:

我使用查询得到下表,现在我想根据下面解释的条件获取单个记录并将其分配给两个变量,即在我的存储过程中声明的 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 为“到期”,则将 v_dte_meeting 分配为“到期”状态的最大日期,并将 v_status_meeting 分配为值“到期”
  2. 如果上述条件失败,则检查 Ststus_Meeting 是否存在单个或多个记录为“Init”,如果存在,则将 v_dte_meeting 分配为“Init”状态的最大日期,并将 v_status_meeting 分配为值“Init”
  3. 如果两个条件都失败,则为两个变量分配 NULL 值

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

【问题讨论】:

  • 您应该编辑您的问题并提供预期的结果。

标签: sql oracle conditional


【解决方案1】:

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

注意 rank() 的使用;在 Gordon 的解决方案中,他将在所有行上获取 max(dte),而不仅仅是那些 status = '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.

【讨论】:

  • 是的。我注意到使用 max(dte) 的日期不正确,您的解决方案运行良好,但只是我不想使用多个外部查询。(我知道 cte 'r ' 可以在此处消除)我已经使用 group by 和单个外部查询以另一种方式完成了它。仍然只是想知道,使用 CTE 是否比子查询有任何性能优势?
  • 仅当您避免在多个地方编写相同的子查询时。否则它可能大致相同(在编译时,“r”无论如何都会被重写为子查询,所以在执行时它没有区别)。最大的区别在于代码的可读性,使其更易于维护。
【解决方案2】:

一种方法使用聚合:

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() 只是为了确保只返回一行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    • 2018-05-25
    • 2015-07-16
    • 2013-05-03
    • 1970-01-01
    相关资源
    最近更新 更多