#sql #oracle #plsql
#sql #Oracle #plsql
Вопрос:
Я пытаюсь написать скрипт PL / SQL, который выполняет несколько инструкций SQL, если определенная таблица существует / не существует.
Например:
SET SERVEROUTPUT ON;
DECLARE
cnt NUMBER := 0;
cnt_2 NUMBER := 0;
BEGIN
SELECT count(*) INTO cnt FROM all_tables where TABLE_NAME='DOES_NOT_EXIST';
IF cnt = 0 THEN
dbms_output.put_line('Table does not exist');
ELSE
dbms_output.put_line('Table exists ' || cnt);
SELECT COUNT(*) INTO cnt_2 from DOES_NOT_EXIST;
END IF;
END;
/
Когда я выполняю это, я получаю сообщение об ошибке ниже
SELECT COUNT(*) INTO cnt_2 from DOES_NOT_EXIST;
*
ERROR at line 10:
ORA-06550: line 10, column 37:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 10, column 5:
PL/SQL: SQL Statement ignored
Но, если я добавлю EXECUTE IMMEDIATE
в строку 11. Тогда все работает нормально.
SET SERVEROUTPUT ON;
DECLARE
cnt NUMBER := 0;
cnt_2 NUMBER := 0;
BEGIN
SELECT count(*) INTO cnt FROM all_tables where TABLE_NAME='DOES_NOT_EXIST';
IF cnt = 0 THEN
dbms_output.put_line('Table does not exist');
ELSE
dbms_output.put_line('Table exists ' || cnt);
EXECUTE IMMEDIATE 'SELECT COUNT(*) INTO cnt_2 from DOES_NOT_EXIST';
END IF;
END;
/
Теперь это работает
Table does not exist
PL/SQL procedure successfully completed.
-
Не могли бы вы, пожалуйста, помочь мне понять, почему сообщается об ошибке, если
ELSE
блок не может быть достигнут логически?cnt
Переменная всегда будет0
, тогда я бы предположил, чтоELSE
блок никогда не будет достигнут. -
Почему добавление
EXECUTE IMMEDIATE
не приводит к ошибке? -
Означает ли это, что я должен добавить
EXECUTE IMMEDIATE
для всех таких операторов вELSE
блоке?
Я искал в SO и других местах, но не смог найти ответ. Честно говоря, я не знаю, какие другие условия поиска использовать. Все поисковые запросы приводят к общим ошибкам. Итак, я задаю этот вопрос. Если на этот вопрос уже дан ответ, пожалуйста, укажите мне на него и закройте это.
Спасибо.
Ответ №1:
Чего вам не хватает, так это того, что инструкции обрабатываются в два этапа; они компилируются перед их выполнением.
На этапе компиляции идентификаторы (таблицы, столбцы и многое другое) идентифицируются и просматриваются. Если имя таблицы (или имя столбца или что-то еще) не найдено, вы получаете ошибку компиляции.
Использование execute immediate
замыкает этот процесс. Вместо «немедленного выполнения» это действительно «задержка компиляции». Инструкция компилируется и выполняется во время выполнения. Вот почему execute immediate
предотвращает ошибку.
Комментарии:
1. Спасибо, Гордон. Есть ли лучший способ закодировать такую логику? или я застрял с добавлением
EXECUTE IMMEDIATE
в блоке ELSE для всех операторов w.r.t в эту таблицу?2. @SantoshSrinivas . , , Я не думаю, что есть альтернатива, если вы хотите ссылаться на несуществующие таблицы.
Ответ №2:
Похоже, вам нужно что-то вроде этого:
select
owner,
table_name,
xmlcast(
xmlquery(
'/ROWSET/ROW/CNT'
passing xmltype(dbms_xmlgen.getXML('select count(*) cnt from "'||owner||'"."'||table_name||'"'))
returning content null on empty
)
as int
) as cnt
from all_tables
where owner in ('XTENDER',user);
Этот запрос возвращает количество строк для каждой таблицы из all_tables, отфильтрованных вашими предикатами