PL- SQL: почему не работает динамический оператор c, использующий ввод переменных связывания? - PullRequest
1 голос
/ 21 января 2020

Я пытаюсь создать и выполнить динамический оператор c SQL (используя Oracle PL / SQL), и когда что-то не работает, я сжал его до следующих двух фрагментов кода:

Насколько я понимаю, следующие два оператора будут эквивалентны (table_name, row_name и row_value - все строки VARCHAR2):

query_statement VARCHAR2(1000);

    -- variant a:
        query_statement := 'select * from ' || table_name || ' where ' || row_name || ' = ' || row_value;
        dbms_output.put_line('query="' || query_statement || '"');        
        execute immediate (query_statement);

    -- variant b:
        query_statement := 'select * from :table where :row = :value';
        dbms_output.put_line('query="' || query_statement || '"');        
        execute immediate (query_statement) using table_name, row_name, row_value;

Но не так! Первый вариант работает нормально, второй всегда дает сбой с ошибкой:

** Обнаружена ошибка: -903 ORA-00903: неверное имя таблицы

Из с точки зрения читабельности Я бы предпочел вариант b, но я не понимаю, почему этот второй вариант дает сбой и почему имя_таблицы помечено как неправильное. Ведь это же имя, очевидно, работает в варианте а. Отправленные запросы также выглядят одинаково для меня - конечно, по модулю тот факт, что вторая строка все еще содержит заполнители только в то время, как первая строка уже содержит конкретные значения.

Может ли какая-то добрая душа пролить свет на это? Почему вариант b не работает? Чего мне не хватает?

Ответы [ 2 ]

2 голосов
/ 21 января 2020

Как уже упоминалось @William, использование переменной bind в качестве Tablename запрещено. В аналогичных строках вы не можете также использовать переменные связывания в качестве предложений Column Names и Order By.

Хотя это нигде не задокументировано, но важно отметить, что замена этих порядковых обозначений влияет на execution plan.

1 голос
/ 21 января 2020

Вы не можете использовать переменную связывания как table_reference. Как указано в ссылке, table_reference должно быть частью c части заявления.

 select * from :table  -- ILLEGAL

Вопреки тому, что использование в предложении WHERE разрешено

 where :row = :value  -- LEGAL, but questionable

, но оно не выполняет то, что вы ожидаете. Предложение where возвращает TRUE, если обе переданные переменные связывания совпадают. Т.е. это эквивалентно

 where 'name' = 'xxxx'

и , а не до

 where name = 'xxxx'
...