Правильный способ проверки наличия строки в таблице [PL / sql block]
вчера я писал некоторые задания, и меня поразило, что я действительно не знаю правильный и принятый способ проверки, существует ли строка в таблице, когда я использую pl / sql.
для примера давайте используем таблицу
PERSON(ID, Name);
Очевидно, Что Я не могу (если нет какого-то секретного метода) что-то вроде:
BEGIN
IF EXISTS SELECT id FROM person WHERE ID = 10;
-- do things when exists
ELSE
-- do things when doesn't exist
END IF;
END;
таким образом, мой стандартный способ решения был:
DECLARE
tmp NUMBER;
BEGIN
SELECT id INTO tmp FROM person WHERE id = 10;
--do things when record exists
EXCEPTION
WHEN no_data_found THEN
--do things when record doesn't exist
END;
однако я не знаю, принят ли это способ делая это, или если есть лучший способ проверить, я бы действительно apprieciate, если бы кто-то мог поделиться своей мудростью со мной :)
Ура.
6 ответов
Я бы не стал вводить обычный код в блок исключений. Просто проверьте, существуют ли какие-либо строки, соответствующие вашему условию, и исходите оттуда:
declare
any_rows_found number;
begin
select count(*)
into any_rows_found
from my_table
where rownum = 1 and
... other conditions ...
if any_rows_found = 1 then
...
else
...
end if;
код IMO с автономным выбором, используемым для проверки наличия строки в таблице, не использует надлежащее преимущество базы данных. В вашем примере у вас есть жестко закодированное значение ID, но это не так, как приложения работают в" реальном мире " (по крайней мере, не в мой мир-ваш может быть другим : -). В типичном приложении вы собираетесь использовать курсор для поиска данных , поэтому предположим, что у вас есть приложение, которое смотрит на данные счета-фактуры и должно знать, существует ли клиент. Основной корпус приложение может быть что-то вроде
FOR aRow IN (SELECT * FROM INVOICES WHERE DUE_DATE < TRUNC(SYSDATE)-60)
LOOP
-- do something here
END LOOP;
и -- do something here
вы хотите найти, если клиент существует, и если не печатать сообщение об ошибке.
один из способов сделать это было бы положить в какой-то синглтон выбрать, как в
-- Check to see if the customer exists in PERSON
BEGIN
SELECT 'TRUE'
INTO strCustomer_exists
FROM PERSON
WHERE PERSON_ID = aRow.CUSTOMER_ID;
EXCEPTION
WHEN NO_DATA_FOUND THEN
strCustomer_exists := 'FALSE';
END;
IF strCustomer_exists = 'FALSE' THEN
DBMS_OUTPUT.PUT_LINE('Customer does not exist!');
END IF;
но ИМО это относительно медленно и подвержено ошибкам. IMO лучший способ (tm) сделать это-включить его в основной курсор:
FOR aRow IN (SELECT i.*, p.ID AS PERSON_ID
FROM INVOICES i
LEFT OUTER JOIN PERSON p
ON (p.ID = i.CUSTOMER_PERSON_ID)
WHERE DUE_DATA < TRUNC(SYSDATE)-60)
LOOP
-- Check to see if the customer exists in PERSON
IF aRow.PERSON_ID IS NULL THEN
DBMS_OUTPUT.PUT_LINE('Customer does not exist!');
END IF;
END LOOP;
этот код рассчитывает на человека.ID объявляется в качестве первичного ключа на PERSON (или по крайней мере, как не NULL); логика заключается в том, что если таблица PERSON внешне присоединена к запросу, а PERSON_ID появляется как NULL, это означает, что строка не была найдена лично для данного CUSTOMER_ID, потому что PERSON.ID должен иметь значение (т. е., по крайней мере, не NULL).
поделиться и наслаждаться.
много способов, чтобы кожа Этот кот. Я помещаю простую функцию в пакет каждой таблицы...
function exists( id_in in yourTable.id%type ) return boolean is
res boolean := false;
begin
for c1 in ( select 1 from yourTable where id = id_in and rownum = 1 ) loop
res := true;
exit; -- only care about one record, so exit.
end loop;
return( res );
end exists;
делает ваши чеки очень чистые...
IF pkg.exists(someId) THEN
...
ELSE
...
END IF;
select nvl(max(1), 0) from mytable;
этот оператор дает 0, если нет строк, 1, Если у вас есть хотя бы одна строка в этой таблице. Это намного быстрее, чем выполнение select count(*). Оптимизатор "видит", что для ответа на вопрос необходимо получить только одну строку.
вот (подробный) небольшой пример:
declare
YES constant signtype := 1;
NO constant signtype := 0;
v_table_has_rows signtype;
begin
select nvl(max(YES), NO)
into v_table_has_rows
from mytable -- where ...
;
if v_table_has_rows = YES then
DBMS_OUTPUT.PUT_LINE ('mytable has at least one row');
end if;
end;
Select 'YOU WILL SEE ME' as ANSWER from dual
where exists (select 1 from dual where 1 = 1);
Select 'YOU CAN NOT SEE ME' as ANSWER from dual
where exists (select 1 from dual where 1 = 0);
Select 'YOU WILL SEE ME, TOO' as ANSWER from dual
where not exists (select 1 from dual where 1 = 0);
Если вы используете явный курсор, он должен быть следующим образом.
DECLARE
CURSOR get_id IS
SELECT id
FROM person
WHERE id = 10;
id_value_ person.id%ROWTYPE;
BEGIN
OPEN get_id;
FETCH get_id INTO id_value_;
IF (get_id%FOUND) THEN
DBMS_OUTPUT.PUT_LINE('Record Found.');
ELSE
DBMS_OUTPUT.PUT_LINE('Record Not Found.');
END IF;
CLOSE get_id;
EXCEPTION
WHEN no_data_found THEN
--do things when record doesn't exist
END;