Oracle: получите запрос, чтобы всегда возвращать ровно одну строку, даже если данных не найдено - PullRequest
7 голосов
/ 13 января 2011

У меня такой запрос:

   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?

(oracle 10g)

Ответы [ 6 ]

18 голосов
/ 13 января 2011

Есть способы сделать это проще и чище, но в основном это объясняет метод:

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
9 голосов
/ 13 января 2011

Я бы предпочел обработать исключение. Однако это будет работать, как вы укажете:

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

Обратите внимание, что это также "работает", если запрос возвращает больше , чем 1 строка - т.е. TOO_MANY_ROWS не вызывается.

1 голос
/ 19 марта 2015

Вот мое простое решение с использованием 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;
1 голос
/ 13 января 2011
 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
0 голосов
/ 01 февраля 2012

https://stackoverflow.com/a/4683045/471149 ответ хороший, но есть более короткое решение

select * from my_table ce, (select 150 as id from dual) d
where d.id = ce.entry_id (+)
0 голосов
/ 13 января 2011

Если вы всегда ожидаете ноль или одну строку, тогда вы можете использовать групповую функцию, т.е.

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

Вы всегда получите хотя бы одну строку и значение NULL в случае, если запись не найдена.

...