【问题标题】:Oracle: Get a query to always return exactly one row, even when there's no data to be foundOracle:获取查询以始终准确返回一行,即使没有数据可找到
【发布时间】:2011-01-13 16:59:08
【问题描述】:

我有一个这样的查询:

   select data_name
   into v_name
   from data_table
   where data_table.type = v_t_id

通常,此查询应该只返回一行。当v_t_id 上没有匹配项时,程序将失败并出现“未找到数据”异常。

我知道我可以在 PL/SQL 中处理此问题,但我想知道是否有办法仅在查询中执行此操作。作为测试,我尝试过:

select case
           when subq.data_name is null then
            'UNKNOWN'
           else
            subq.data_name
       end
from (select data_name
       from data_table
       where data_table.type = '53' /*53 does not exist, will result in 0 rows. Need fix this...*/
       ) subq;

...但这显然行不通(因为subq 为空与subq.data_name is null 不同)。这甚至可能吗,还是我应该只签入我的 PL/SQL 解决方案?

(甲骨文 10g)

【问题讨论】:

  • 如果查询不返回任何行,您期望/希望 data_name 具有什么值?这是处理未找到数据情况的挑战。
  • @Thomas:字符串“UNKNOWN”在这种情况下可以正常工作。

标签: sql oracle ora-01403


【解决方案1】:

有一些方法可以让这个更简单、更干净,但这基本上说明了技术:

SELECT data_name
FROM data_table
WHERE data_table.type = v_t_id

UNION ALL

SELECT NULL AS data_name
FROM dual
WHERE NOT EXISTS (
    SELECT data_name
    FROM data_table
    WHERE data_table.type = v_t_id
)

当联合的第一部分为空时,第二部分将包含一行,当第一部分不为空时,第二部分将不包含任何行。

如果查询需要很长时间,请使用这个:

SELECT * FROM (  
    SELECT data_name
    FROM data_table
    WHERE data_table.type = v_t_id

    UNION ALL

    SELECT NULL AS data_name
    FROM dual
  ) WHERE data_name is not null or ROWNUM = 1

【讨论】:

  • 我喜欢这个,NOT EXISTS 让整个事情的意思很清楚。
【解决方案2】:

我更愿意处理异常。但是,这将按照您的指定工作:

select min(data_name) data_name
into v_name
from data_table
where data_table.type = v_t_id

请注意,如果查询返回更多多于 1 行,这也“有效” - 即未引发 TOO_MANY_ROWS。

【讨论】:

    【解决方案3】:
     select coalesce(data_table.data_name, d.data_name) data_name
       into v_name
       from 
       (SELECT 'UNKNOWN ' as data_name FROM DUAL)  d
       LEFT JOIN data_table
       ON data_table.type = v_t_id
              or a.data_table.data_name is null
    

    【讨论】:

      【解决方案4】:

      这是我使用 LEFT OUTER JOIN 的简单解决方案:

      CREATE TABLE data_table(data_name VARCHAR2(20), data_type NUMBER(2));
      
      INSERT INTO data_table(data_name, data_type) VALUES('fifty-one', 51);
      
      SELECT coalesce(data_name, 'unknown')
        FROM dual
        LEFT OUTER JOIN (SELECT data_name FROM data_table WHERE data_type = 53) o
          ON 1 = 1;
      
      SELECT coalesce(data_name, 'unknown')
        FROM dual
        LEFT OUTER JOIN (SELECT data_name FROM data_table WHERE data_type = 51) o
          ON 1 = 1;
      

      【讨论】:

        【解决方案5】:

        https://stackoverflow.com/a/4683045/471149 答案很好,但有更短的解决方案

        select * from my_table ce, (select 150 as id from dual) d
        where d.id = ce.entry_id (+)
        

        【讨论】:

          【解决方案6】:

          如果您总是期望零行或一行,那么您可以使用组函数,即:

          select dump(max(dummy)) from dual
          where dummy = 'Not Found'
          

          在未找到记录的情况下,您将始终获得至少一行和 NULL 值。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-01
            • 2019-12-13
            • 2011-02-19
            • 2016-10-24
            • 2013-12-20
            相关资源
            最近更新 更多