Oracle: Get a query to always return exactly one row, even when there's no data to be found

China☆狼群 提交于 2019-12-04 03:13:32

问题


I have a query like this:

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

Normally, this query should return exactly one row. When there's no match on v_t_id, the program fails with a "No data found" exception.

I know I could handle this in PL/SQL, but I was wondering if there's a way to do this only in a query. As a test, I've tried:

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;

...but this will obviously not work (because subq being empty is not the same as subq.data_name is null). Is this even possible or should I just check in my PL/SQL solution?

(oracle 10g)


回答1:


There's ways to make this simpler and cleaner, but this basically spells out the technique:

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
)

When the first part of the union is empty the second will contain a row, when the first part is not empty, the second will contain no rows.

If the query is takes to much time, use this one:

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



回答2:


I would prefer to handle the exception. However, this would work as you specify:

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

Note that this also "works" if the query returns more than 1 row - i.e. TOO_MANY_ROWS is not raised.




回答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:


Here is my simple solution using 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:


If you always expect zero or one row then you can use a group function i.e.:

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

You will always get at least one row and a value of NULL in the case where the record is not found.




回答6:


https://stackoverflow.com/a/4683045/471149 answer is nice, but there is shorter solution

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


来源:https://stackoverflow.com/questions/4682821/oracle-get-a-query-to-always-return-exactly-one-row-even-when-theres-no-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!