2016-06-06 3 views
0

У меня есть некоторый код, как это:динамический SQL в PLSQL

declare 
p_vara varchar2; 
p_varb varchar2; 
p_varc varchar2; 
begin 

INSERT INTO MY_INSERTABLE_TABLE 
SELECT a.id,b.id,c.id 
FROM table_a a, table_b b, table_c c 
WHERE a.id is not null 
     and a.id = b.id 
     and c.id = 'cat' 
end; 

Теперь на основе переменной, чтобы сделать его условным, так что только некоторые части запроса дозвонились на основе переменной.

declare 
p_vara varchar2; 
p_varb varchar2; 
p_varc varchar2; 
begin 

INSERT INTO MY_INSERTABLE_TABLE 
SELECT a.id, -- Show only if p_vara = 'yes' 
     b.id, -- Show only if p_varb = 'yes' 
     c.id -- Show only if p_varc = 'yes' 
FROM table_a a, -- Use only if p_vara = 'yes' 
    table_b b, -- Use only if p_varb = 'yes' 
    table_c c -- Use only if p_varc = 'yes' 
WHERE a.id is not null -- Use only if p_vara = 'yes' 
     and a.id = b.id -- Use only if p_vara = 'yes' and p_varb = 'yes' 
     and c.id = 'cat' -- Use only if p_varc = 'yes' 
end; 

Так, например, если переменные установлены, как это:

p_vara = 'yes' 
p_varb = 'no' 
p_varc = 'no' 

Тогда запрос должен выглядеть следующим образом:

SELECT a.id  
FROM table_a 
WHERE a.id is null; 
+0

К сожалению, это всего лишь пример. Я изменил a.id: null, чтобы a.id не был нулевым. Должен работать сейчас. – user2924127

+0

Это не фильтрация запроса. То, что вы ищете, - это динамический SQL, где сама заявка зависит от определенного определенного ввода. В качестве части динамического SQL вы должны указать динамический список столбца, который вы вставляете, если только ваш MY_INSERTABLE_TABLE имеет только один столбец, а 'p_vara',' p_varb' и 'p_varc' являются взаимоисключающими, что на основе вашей второй predicate 'и a.id = b.id - Использовать только в том случае, если p_vara = 'yes' и p_varb = 'yes'' неверно – Sentinel

+0

У вас действительно есть только 3 переменные и в общей сложности 8 возможных комбинаций? В этот момент может быть проще просто ввести 8 отдельных статических операторов SQL. Например, ваш полный запрос объединяет 3 таблицы, но имеет только 1 условие соединения, поэтому он будет создавать декартово произведение. Если 'p_vara = 'yes' и p_varc = 'yes'', это создаст декартово произведение между' table_a' и 'table_c'. Маловероятно, что это было бы то, что вы хотите. –

ответ

2

Как написано, ваши требования не кажутся полный. Если все три переменные равны yes, например, ваш полный оператор будет иметь три объединения таблиц, но только одно условие соединения, чтобы вы могли создать декартовский продукт с table_c. Если p_vara = 'yes' and p_varc = 'yes', у вас будет две таблицы, объединенные без условия соединения, так что у вас снова будет декартово произведение. Мне кажется маловероятным, что вы действительно хотите создать декартовский продукт.

В общем, вы можете построить инструкцию SQL в строковой переменной, а затем передать это значение EXECUTE IMMEDIATE. Если у вас есть 25 логических переменных, это означает, что ваш код может генерировать в общей сложности 33,55 миллиона различных SQL-операторов. Просто проверяя, что ни один из этих путей не генерирует оператор с синтаксическими ошибками, будет нетривиальным. В сочетании с тем фактом, что прибегать к динамическому SQL обычно делает код более сложным для чтения, поддержки и поддержки в дополнение к созданию возможностей для производительности и безопасности, я хотел бы вернуться к любому дизайну, который предполагает нечто сложное, как то, что вы описываете ,

Что сказал, вы могли бы сделать что-то вроде этого (я не строить пункт WHERE полностью, но я надеюсь, что вы получите тэк)

declare 
    l_vara boolean; 
    l_varb boolean; 
    l_varc boolean; 

    l_sql_stmt varchar(4000); 
begin 
    l_sql_stmt := 'INSERT INTO my_insertable_table(col1, col2, col3) '; 
    l_sql_stmt := l_sql_stmt || ' SELECT ' || 
       (case when l_vara then ' a.id, ' else ' null, ' end) || 
       (case when l_varb then ' b.id, ' else ' null, ' end) || 
       (case when l_varc then ' c.id, ' else ' null, ' end); 
    l_sql_stmt := rtrim(l_sql_stmt, ','); -- remove the extra trailing comma 
    l_sql_stmt := l_sql_stmt || ' FROM '; 

    if(l_vara) 
    then 
    l_sql_stmt := l_sql_stmt || ' table_a a, '; 
    end if; 
    if(l_varb) 
    then 
    l_sql_stmt := l_sql_stmt || ' table_b b, '; 
    end if; 
    if(l_varc) 
    then 
    l_sql_stmt := l_sql_stmt || ' table_c c, '; 
    end if; 

    -- again remove the extra trailing comma 
    l_sql_stmt := rtrim(l_sql_stmt, ','); 

    <<build out the WHERE clause similarly>> 

    -- Log the SQL statement so you can debug it when it fails 
    insert into some_log_table(sql_stmt) values(l_sql_stmt); 

    EXECUTE IMMEDIATE l_sql_stmt; 
end; 
Смежные вопросы