Oracle: получите запрос, чтобы всегда возвращать ровно одну строку, даже если данные не найдены
У меня есть такой запрос:
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?
(оракул 10 г)
6 ответов
Есть способы сделать это проще и чище, но в основном это объясняет технику:
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
Я предпочел бы обработать исключение. Однако это будет работать так, как вы укажете:
select min(data_name) data_name
into v_name
from data_table
where data_table.type = v_t_id
Обратите внимание, что это также "работает", если запрос возвращает более 1 строки - т.е. TOO_MANY_ROWS не вызывается.
Вот мое простое решение с использованием 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;
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
/questions/37113571/oracle-poluchite-zapros-chtobyi-vsegda-vozvraschat-rovno-odnu-stroku-dazhe-esli-dannyie-ne-najdenyi/37113608#37113608 ответ хороший, но есть более короткое решение
select * from my_table ce, (select 150 as id from dual) d
where d.id = ce.entry_id (+)
Если вы всегда ожидаете ноль или одну строку, то вы можете использовать групповую функцию, т.е.
select dump(max(dummy)) from dual
where dummy = 'Not Found'
Вы всегда получите хотя бы одну строку и значение NULL в случае, если запись не найдена.