Oracle PL/SQL游标的变量/文字替换?
我经常不得不在Oracle PL/SQL中调试游标。我的问题是,我最终会有几百行大游标,其中包含50多个变量和常量。我正在寻找一种方法来获取语句的一个版本,其中常量和变量被替换为它们的文本。如果我想知道为什么光标没有显示记录/行,那么我应该在30分钟内替换这些变量/文字,然后才能运行select并注释掉一些语句以找出错误 所以如果我有Oracle PL/SQL游标的变量/文字替换?,oracle,plsql,cursors,Oracle,Plsql,Cursors,我经常不得不在Oracle PL/SQL中调试游标。我的问题是,我最终会有几百行大游标,其中包含50多个变量和常量。我正在寻找一种方法来获取语句的一个版本,其中常量和变量被替换为它们的文本。如果我想知道为什么光标没有显示记录/行,那么我应该在30分钟内替换这些变量/文字,然后才能运行select并注释掉一些语句以找出错误 所以如果我有 CURSOR cFunnyCursor ( v1 NUMBER, v2 NUMBER ) IS SELECT * FROM TABLE WHERE co
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';
有没有办法以这种方式获取/记录SELECT,这样我就可以在新的SQL窗口中复制粘贴它,这样我就不必花30分钟来替换这些东西?(应该是我可以重用的东西,它不绑定到特殊的游标,因为我经常需要在大量不同的游标上使用这些东西)。我这样做的方法是将sql复制并粘贴到编辑器窗口中,在所有变量前面加上:然后运行查询。当我使用Toad时,我会得到一个窗口,提示我输入查询中所有绑定变量的值,因此我填写这些值,然后查询运行。值已保存,因此可以无需太多麻烦地重新运行查询,或者如果需要调整值,也可以这样做 e、 g: 变成
SELECT * FROM TABLE
WHERE col1 = :v1
AND col2 != :v2
AND col3 = :CONSTANT;
下面的函数使用GV$SQL\u bind\u CAPTURE中的数据将绑定变量替换为最近的文本。Oracle绑定元数据并非始终可用,因此下面的函数可能无法用于所有查询 创建函数: 运行函数: Oracle只捕获绑定变量的第一个实例。在运行清除现有绑定数据的过程之前,请运行此语句。在生产环境中运行此语句时要小心,它可能会暂时降低系统速度,因为它丢失了缓存的计划
alter system flush shared_pool;
现在找到SQL_ID。这可能很棘手,取决于SQL的通用性或唯一性
select *
from gv$sql
where lower(sql_fulltext) like lower('%unique_string%')
and sql_fulltext not like '%quine%';
最后,将SQL插入到过程中,它应该返回带有文本的代码。不幸的是,SQL丢失了所有格式。这是不容易的。如果这是一个巨大的任务,那么您可以使用PL/Scope来替代过程中的变量来构建一些东西,但我觉得这会非常复杂。希望您的IDE有一个代码美化器
select get_sql_with_literals(p_sql_id => '65xzbdjubzdqz') sql
from dual;
完整示例和一个过程:
我修改了您的源代码并添加了唯一标识符,以便可以轻松找到查询。我使用了一个提示,因为解析的查询不包含常规注释。我还更改了数据类型,以包括字符串和日期,从而使示例更真实
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;
/
begin
test_procedure;
end;
/
select *
from gv$sql
where lower(sql_fulltext) like lower('%unique_string%')
and sql_fulltext not like '%quine%';
结果:
select get_sql_with_literals(p_sql_id => '65xzbdjubzdqz') sql
from dual;
SQL
---
SELECT /*+ unique_string_1 */ * FROM TEST1 WHERE COL1 = 3 AND COL2 != 'asdf' AND COL3 = to_date('01/01/2000 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
我认为您必须使用动态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;
如果你有一个更大的游标查询,这不是一个有效的方法。因为您可能需要将整个游标查询替换为动态SQL 一种可能的方法是将光标分配给SYS\u REFCURSOR变量,然后将SYS\u REFCURSOR分配给bind变量 如果在Toad中运行此代码段,将要求您在弹出窗口中定义:out变量:只需选择方向:out/Type:CURSOR,数据集将显示在“数据网格”选项卡中
其他SQL IDE也应该支持此功能。我仍然需要进入例程,将所有这些变量复制/粘贴到提示符中,并将:置于每个变量的前面。这并不比用鼠标->ctfl+f,搜索/替换并输入正确的变量来选择变量名快多少。我需要一些能代替我的东西。我同意你的看法,这不会节省你很多时间。。。你第一次这么做的时候。但是,如果您必须经常调试这些查询,那么我会保存查询的调试版本(即,在所有:’都已就绪的情况下),并从上一次运行(无论如何,在Toad中)中记住这些值。我的问题是,在这种情况下,客户机调用某个查询是因为某些操作不起作用。我意识到记录/行不在记录集中,我必须找出原因。我们的数据库中有一大堆乱七八糟的游标,其中有大量的变量。所以我花了30分钟来替换变量,花了30秒来注释出一些行来找出问题。这种情况不是很令人满意,所以我需要一个变通方法。好主意,我的IDE有一个代码美化器。问题是它创建了一个损坏的select。我在不属于它们的地方得到了一些变量。@aLpenbog一个潜在的问题是替换可能是意外地替换了子字符串。例如,“:b10”可能已被“:b1”的值替换。我改变了顺序,先匹配最大的字符串。可能会有一些性能开销,但这可能是可以忍受的。将查询转换为返回引用游标的过程(或函数)。此过程的参数将与当前过程相同。转换现有代码以调用此新过程。现在,您可以在不使用周围代码的情况下进行调试,只查看查询本身生成了什么。您还可以在此新过程中添加一个额外的调试标志(默认为否),该标志允许您在调试时记录参数,但在正常生产运行期间不记录参数。
select get_sql_with_literals(p_sql_id => '65xzbdjubzdqz') sql
from dual;
SQL
---
SELECT /*+ unique_string_1 */ * FROM TEST1 WHERE COL1 = 3 AND COL2 != 'asdf' AND COL3 = to_date('01/01/2000 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
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;
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;