#oracle #plsql
#Oracle #plsql
Вопрос:
Более широкая история
Я создаю автоматический сортировщик запросов моих учеников. Я буду запускать и останавливать контейнеры Docker для каждого учащегося и уже знаю, как построить систему вокруг него. Я отправлю запрос непосредственно в контейнер базы данных вместе с моим собственным правильным запросом.
Вопрос
Я хотел бы иметь 2 вещи при сравнении двух запросов:
- флажок, который переключает «Порядок столбцов важен, да / нет»
- флажок, который переключает «Порядок строк важен, да / нет»
Это то, что у меня есть для этой «основной» части.
sqlplus -s system/oracle@localhost:1521/xe <<EOF
set feedback off trimspool on;
spool result.txt;
(select * from cities) MINUS (select id, name from cities);
spool off;
exit;
EOF
Мне нужны некоторые предложения. Как бы вы сравнили два запроса, когда порядок столбцов не важен? Как насчет порядка строк, нужно ли мне принудительно упорядочивать в каждой задаче? Каков наилучший подход для предоставления более автоматической обратной связи, просто вывод ошибок компилятора?
Я буду признателен за каждый совет.
PS Я уже сделал свою долю поиска в Google, но без особой удачи для pl / sql.
Комментарии:
1. А? Не понимаю. вы ссылаетесь на таблицу table в операции МИНУС.
2. Слева от МИНУСА приведен пример кода моего ученика, а правая часть МИНУСА — моя (правильная). В этом примере, если у нас обоих одинаковый результирующий набор, file result.txt будет пусто. В противном случае наши результаты будут отличаться.
3. вам придется использовать одни и те же столбцы, иначе как МИНУС узнает, похожа ли строка. Я не думаю, что порядок строк необходим.
4. Оператор MINUS требует одинакового количества столбцов одного и того же типа в том же порядке, иначе он не будет работать. Вам нужно будет динамически создавать оператор с помощью регулярного выражения и использовать немедленное выполнение, если вы пытаетесь сделать это таким образом.
Ответ №1:
Вы можете использовать DBMS_SQL
package для создания курсора и получения имен столбцов. Что касается порядка строк, моим первым предположением было использовать ROWNUM
псевдоколоночный и после добавления его использования MINUS
. Но проблема в том, что единственный способ гарантировать упорядочение — это использовать ORDER BY
, и я не могу сгенерировать правильную ORDER BY
часть во внешнем выборе после замены столбцов. Поместить этот столбец после SELECT
подстроки плохо, потому что тогда им трудно управлять UNION
. Вы можете попросить поместить некоторый фиктивный столбец в самый верхний SELECT
, который затем вы можете заменить, ROWNUM as rn
а затем продолжить. Или выполните оба курсора и попробуйте сравнить их строка за строкой.
Код, который я получаю, приведен ниже. Здесь вы можете попробовать это.
declare
v_sql_t varchar(32000) := 'select 1 as a, ''q'' as b from dual union all select 2, ''a'' from dual order by 1';
v_sql_s varchar(32000) := 'select 1 as a, ''q'' as b from dual union all select 2, ''a'' from dual order by 2';
v_cursor integer;
v_col_count integer;
v_cols_t dbms_sql.desc_tab;
v_cols_s dbms_sql.desc_tab;
v_cols_select varchar2(32000);
v_select_keyword_begin integer;
v_final_select varchar2(32000);
v_col_order integer := 1;
v_row_order integer := 1;
begin
v_cursor := dbms_sql.open_cursor;
dbms_sql.parse(v_cursor, v_sql_t, dbms_sql.native);
dbms_sql.describe_columns(v_cursor, v_col_count, v_cols_t);
dbms_sql.parse(v_cursor, v_sql_s, dbms_sql.native);
dbms_sql.describe_columns(v_cursor, v_col_count, v_cols_s);
--Check column order
for i in 1..v_cols_t.count loop
if v_col_order > 0 and v_cols_t(i).col_name != v_cols_s(i).col_name then
dbms_output.put_line('Wrong column order. Should be: ' || v_cols_t(i).col_name || ', got ' || v_cols_s(i).col_name);
end if;
if i = 1 then
v_cols_select := v_cols_t(i).col_name;
else
v_cols_select := v_cols_select || ',' || v_cols_t(i).col_name;
end if;
end loop;
if v_row_order > 0 then
v_cols_select := v_cols_select || ', rownum as rn';
end if;
v_final_select := 'with t as ( select ' || v_cols_select || ' from (' || v_sql_t || ' ) )' || chr(10)
|| ', s as ( select ' || v_cols_select || ' from (' || v_sql_s || ' ) )' || chr(10)
|| ', t_s as (select * from t minus select * from s)' || chr(10)
|| ', s_t as (select * from s minus select * from t)' || chr(10)
|| 'select ''T'' as src, t_s.* from t_s
union all
select ''S'' as src, s_t.* from s_t';
dbms_output.put_line(v_final_select);
end;
/