2015-12-04 3 views
4

Мне часто приходится отлаживать курсоры в Oracle PL/SQL. Моя проблема заключается в том, что в итоге я получаю несколько высокоразмерных строк с большими курсорами, такими как 50 + переменные и константы. Я ищу способ получить версию утверждения, где константы и переменные заменяются их литералами. Если я хочу узнать, почему курсор не показывает запись/строку, я должен закончить замену этих переменных/литералов в течение 30 минут, прежде чем я смогу запустить выбор и прокомментировать некоторые из утверждений, чтобы выяснить, что не так.Переменная/буквенная замена для курсоров PL/SQl?

Так что, если у меня есть что-то вроде

CURSOR cFunnyCursor (
    v1 NUMBER, 
    v2 NUMBER 
) IS 
SELECT * FROM TABLE 
WHERE col1 = v1 
AND col2 != v2 
AND col3 = CONSTANT; 

мне нужно ВЫБРАТЬ так:

SELECT * FROM TABLE 
WHERE col1 = 123 
AND col2 != 5324 
AND col3 = 'ValueXyz'; 

есть ли способ, чтобы получить/регистрировать ВЫБРАТЬ таким образом, чтобы я мог просто скопировать пасты это в новом окне SQL, поэтому мне не нужно тратить 30 минут, чтобы заменить этот материал? (должно быть что-то, что я могу повторить, это не привязка к этому специальному курсору, потому что мне это нужно довольно часто на тонну разных курсоров).

ответ

0

Способ, которым я делаю это, заключается в том, чтобы скопировать и вставить sql в окно редактора, добавьте все переменные с помощью: и затем запустите запрос. Когда я использую Toad, я получаю окно, предлагающее мне значения для всех переменных связывания в запросе, поэтому я заполняю их и запускает запрос. Значения сохраняются, поэтому запрос может быть повторно запущен без особых хлопот, или если вам нужно настроить значение, вы можете сделать.

.: например

SELECT * FROM TABLE 
WHERE col1 = v1 
AND col2 != v2 
AND col3 = CONSTANT; 

становится

SELECT * FROM TABLE 
WHERE col1 = :v1 
AND col2 != :v2 
AND col3 = :CONSTANT; 
+0

Я все равно должен был бы войти в процедуру и скопировать/вставить все эти переменные в приглашение и поставить: infront каждой переменной. Это не намного быстрее, чем выбор имени переменной с помощью мыши -> ctfl + f, поиск/замена и установка правильной переменной. Мне нужно что-то, что делает эту замену для меня. – aLpenbog

+0

Я согласен с вами относительно замены, это не сэкономит вам много времени ... в первый раз, когда вы это сделаете. Но если вам нужно довольно часто отлаживать эти запросы, я бы сохранил отладочную версию запроса (т. Е. Со всеми: »на месте), и значения запоминаются из предыдущего прогона (в любом случае, Toad) – Boneist

+0

Моя проблема заключается в ситуации, когда клиент звонит, потому что что-то не работает. Я понимаю, что запись/строка не находится внутри набора записей, и я должен выяснить, почему. У нас есть тонна действительно больших грязных курсоров в нашей базе данных с s..load переменных. Так что мне нужно 30 минут, чтобы заменить переменные и как 30 секунд, чтобы прокомментировать некоторые строки, чтобы выяснить проблему. Эта ситуация не очень удовлетворяет, поэтому мне нужно обходное решение. – aLpenbog

0

Литеральные версии курсоров могут быть получены с использованием данных из GV $ SQL_BIND_CAPTURE. По моему опыту, метаданные привязки Oracle bind не всегда доступны; приведенный ниже код работает с образцом курсора, но может быть недостаточно прочным для работы со всем кодом.

Пример схемы, уникальная строка

Изменить исходный код и добавить уникальные идентификаторы запросов, чтобы они могли быть программно выбран. Используйте подсказку, потому что анализируемая версия запроса не будет содержать регулярные комментарии. Я изменил типы данных, чтобы включить строки и даты, чтобы сделать пример более реалистичным.

drop table test1 purge; 
create table test1(col1 number, col2 varchar2(100), col3 date); 

create or replace procedure test_procedure is 
    C_Constant constant date := date '2000-01-01'; 
    v_output1 number; 
    v_output2 varchar2(100); 
    v_output3 date; 

    CURSOR cFunnyCursor (
     v1 NUMBER, 
     v2 VARCHAR2 
    ) IS 
    SELECT /*+ unique_string_1 */ * FROM TEST1 
    WHERE col1 = v1 
    AND col2 != v2 
    AND col3 = C_CONSTANT; 
begin 
    open cFunnyCursor(3, 'asdf'); 
    fetch cFunnyCursor into v_output1, v_output2, v_output3; 
    close cFunnyCursor; 
end; 
/

Промойте Shared Pool

Oracle захватывает только первый экземпляр связываемых переменных. Запустите этот оператор перед запуском процедуры для очистки существующих данных привязки.

alter system flush shared_pool; 

Запуск процедуры испытания

begin 
    test_procedure; 
end; 
/

PL/SQL блок для генерации SQL Буквенный

--Print a query with literals instead of binds. 
declare 
    --Change this to match the query. 
    v_unique_string varchar2(100):= 'unique_string_1'; 

    v_sql_id varchar2(100); 
    v_sql_text clob; 
begin 
    --Get the SQL_ID and text. 
    select sql_id, sql_fulltext 
    into v_sql_id, v_sql_text 
    from gv$sql 
    where lower(sql_text) like '%'||v_unique_string||'%' 
     and sql_text not like '%quine%'; 

    --Loop through the binds. 
    for binds in 
    (
     select * 
     from gv$sql_bind_capture 
     where sql_id = v_sql_id 
     --Match longest names first to avoid matching substrings. 
     --For example, we don't want ":b1" to be matched to ":b10". 
     order by length(name) desc, position 
    ) loop 
     --Convert the value from a string to a literal. 
     if binds.datatype_string = 'NUMBER' then 
      v_sql_text := replace(v_sql_text, binds.name, binds.value_string); 
     elsif binds.datatype_string like 'VARCHAR2%' then 
      v_sql_text := replace(v_sql_text, binds.name, ''''||binds.value_string||''''); 
     --Adjust this to match your server date format. 
     elsif binds.datatype_string like 'DATE%' then 
      v_sql_text := replace(v_sql_text, binds.name, 'to_date('''||binds.value_string||''', ''MM/DD/YYYY HH24:MI:SS'')'); 
     --TODO: Add more types here. 
     end if; 
    end loop; 

    --Remove the unique string so it's not re-run with the literal version. 
    v_sql_text := replace(v_sql_text, v_unique_string, null); 

    --Print the SQL. 
    dbms_output.put_line(v_sql_text); 
end; 
/

Результат

SELECT /*+ */ * FROM TEST1 WHERE COL1 = 3 AND COL2 != 'asdf' AND COL3 = to_date('01/01/2000 00:00:00', 'MM/DD/YYYY HH24:MI:SS') 

К сожалению, он потерял все форматирование. Это не так просто. Если это огромная сделка, вы можете создать что-то, используя PL/Scope, чтобы заменить переменные в процедуре, но у меня такое чувство, что это было бы смешно сложно. Надеемся, что у вашей среды IDE есть улучшитель кода.

+0

Отличная идея, и моя IDE имеет улучшитель кода. Проблема в том, что он создает коррумпированный выбор. Я получаю переменные в тех местах, где они не принадлежат. – aLpenbog

+0

@aLpenbog Одна из потенциальных проблем заключается в том, что замена, возможно, случайно заменила подстроки. Например, «: b10» может быть заменено значением «: b1». Я изменил порядок, чтобы сначала совместить самые большие строки. –

0

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

DECLARE 
vString VARCHAR2 (32000); 
vResult sys_refcursor; 
BEGIN 
vString := 
    'SELECT * FROM table 
     WHERE col1 = '|| v1|| ' 
     AND col2 != '|| v2|| ' 
     AND col3 = '|| v; 

OPEN vResult FOR vString; 

DBMS_OUTPUT.put_line (vString); 
END; 

Если у вас есть большой запрос на курсор, это не эффективный способ. Поскольку вам может потребоваться заменить весь запрос Cursor на Dynamic SQL.