我经常需要在Oracle PL / SQL中调试游标。我的问题是,我最终得到了一些带有50多个变量和常量的数字游标。我正在寻找一种获取语句版本的方法,其中常量和变量用其文字替换。如果我想找出为什么光标没有显示记录/行,我应该最终替换那些变量/文字30分钟才能运行select并注释掉一些语句以找出&# 39;错了。
所以,如果我有类似
的东西SELECT * FROM TABLE
WHERE col1 = 123
AND col2 != 5324
AND col3 = 'ValueXyz';
我需要像这样的SELECT:
{{1}}
有没有办法以这种方式获取/记录SELECT所以我可以将它复制粘贴到一个新的SQL窗口中,这样我就不用花30分钟来替换那些东西了? (应该是我可以重用的东西,并没有绑定到那个特殊的游标,因为我经常在大量不同的游标上需要这些东西)。
答案 0 :(得分:0)
我这样做的方法是将sql复制并粘贴到编辑器窗口中,在所有变量前加上:然后运行查询。当我使用Toad时,我得到一个窗口提示我查询中所有绑定变量的值,所以我填写它们并运行查询。保存了值,因此可以轻松地重新运行查询,或者如果需要调整值,则可以执行此操作。
e.g:
SELECT * FROM TABLE
WHERE col1 = v1
AND col2 != v2
AND col3 = CONSTANT;
变为
SELECT * FROM TABLE
WHERE col1 = :v1
AND col2 != :v2
AND col3 = :CONSTANT;
答案 1 :(得分:0)
可以使用GV $ SQL_BIND_CAPTURE中的数据生成游标的文字版本。根据我的经验,Oracle绑定捕获元数据并不总是可用;下面的代码适用于示例游标,但可能不够强大,无法使用所有代码。
示例架构,唯一字符串
修改源代码并为查询添加唯一标识符,以便以编程方式选择它们。使用提示,因为查询的解析版本不包含常规注释。我更改了数据类型以包含字符串和日期,以使示例更加真实。
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;
/
刷新共享池
Oracle仅捕获绑定变量的第一个实例。在运行该过程之前运行此语句以清除现有绑定数据。
alter system flush shared_pool;
运行测试程序
begin
test_procedure;
end;
/
生成文字SQL的PL / 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具有代码美化功能。
答案 2 :(得分:0)
我认为您必须使用动态SQL功能来获取这些变量值。通过使用ref cursor变量,您甚至可以看到输出 请查看以下查询。
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查询,它不是一种有效的方法。因为您可能需要将整个Cursor查询替换为Dynamic SQL。
答案 3 :(得分:0)
一种可能的方法是将光标辅助到SYS_REFCURSOR变量,然后将SYS_REFCURSOR分配给绑定变量。
如果您在Toad中运行此代码段,则将要求您在弹出窗口中定义:out变量:只需选择Direction:OUT / Type:CURSOR,然后数据集将显示在“ Data Grid”中标签。
declare
l_refcur sys_refcursor;
v1 varchar2(4) := 'v1';
v2 varchar2(4) := 'v2';
c_constant varchar2(4) := 'X';
begin
open l_refcur for
SELECT * FROM dual
WHERE dummy = c_CONSTANT;
:out := l_refcur;
end;
其他SQL IDE也应支持此功能。