Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle PL/SQL游标的变量/文字替换?_Oracle_Plsql_Cursors - Fatal编程技术网

Oracle PL/SQL游标的变量/文字替换?

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

我经常不得不在Oracle PL/SQL中调试游标。我的问题是,我最终会有几百行大游标,其中包含50多个变量和常量。我正在寻找一种方法来获取语句的一个版本,其中常量和变量被替换为它们的文本。如果我想知道为什么光标没有显示记录/行,那么我应该在30分钟内替换这些变量/文字,然后才能运行select并注释掉一些语句以找出错误

所以如果我有

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;