程序主体内的光标

Posted

技术标签:

【中文标题】程序主体内的光标【英文标题】:Cursor inside procedure body 【发布时间】:2015-10-27 10:48:52 【问题描述】:

我试图在过程体中声明一个游标。 我知道它应该在声明块中完成,但是游标引用的表是在过程主体内创建的。

--TABLE MAY OR MAY NOT BE PRESENT PRIOR TO PROCEDURE EXECUTION
SELECT COUNT(*)
  INTO ln_cnt
  FROM User_Tables
  WHERE table_name = 'TMP$UOM_COMBO_GEN';
  IF ln_cnt > 0 THEN
    EXECUTE IMMEDIATE ' CREATE TABLE TMP$UOM_COMBO_GEN (UOM_ID VARCHAR2(20 BYTE), HIER_CODE VARCHAR2(20 BYTE),NODE_CODE VARCHAR2(200 BYTE))';
  END IF;

  CURSOR C_HIER
  IS
    SELECT DISTINCT HIER_CODE FROM TMP$UOM_COMBO_GEN WHERE UOM_ID=P_UOM_ID;

 FOR HIER IN C_HIER
  LOOP
    IF C_HIER%ROWCOUNT = 1 THEN
      LV_SQL2         := '(SELECT UOM_ID, NODE_CODE '||HIER.HIER_CODE||' FROM TMP$UOM_COMBO_GEN WHERE UOM_ID='''||P_UOM_ID||''' AND HIER_CODE='''||HIER.HIER_CODE||''')'||HIER.HIER_CODE;
      LV_SORT         := ' ORDER BY '||HIER.HIER_CODE||'';
      LV_SQL          := 'SELECT * FROM ' || LV_SQL2;
    ELSE
      LV_SQL3 := ' LEFT OUTER JOIN(SELECT NODE_CODE '||HIER.HIER_CODE||' FROM TMP$UOM_COMBO_GEN WHERE UOM_ID='''||P_UOM_ID||''' AND HIER_CODE='''||HIER.HIER_CODE||''')'||HIER.HIER_CODE ||' ON 1=1';
      LV_SORT := LV_SORT||','||HIER.HIER_CODE||'';
      LV_SQL  := LV_SQL || LV_SQL3;
    END IF;
  END LOOP;

我收到以下错误。

错误(17,10):PLS-00103:在预期以下之一时遇到符号“C_HIER”::=。 (@%;

【问题讨论】:

如果动态创建表,总是要使用动态SQL来引用它。不能使用静态 SQL 打开游标。你为什么首先使用动态 SQL 来创建表?在运行时创建对象通常是一种非常糟糕的方法,所以我最初的偏见是摆脱这种方法。如果TMP$ 表示一个临时表,而您实际上需要一个表对象而不是集合,则创建一次全局临时表并像使用任何其他表一样使用它。 【参考方案1】:

一个表一旦创建就存储在数据库中,你可以从你想在模式中引用的任何地方引用它。

您的代码可能需要在以下部分进行更改

        SELECT COUNT(*)
          INTO ln_cnt
          FROM User_Tables
          WHERE table_name = 'TMP$UOM_COMBO_GEN';
          IF ln_cnt > 0 THEN -- means only if table exists u want to create the table which will 
         --throw an exception if table is already there , 
         --so better equate it to 0
            EXECUTE IMMEDIATE ' CREATE TABLE TMP$UOM_COMBO_GEN (UOM_ID VARCHAR2(20 BYTE), HIER_CODE VARCHAR2(20 BYTE),NODE_CODE VARCHAR2(200 BYTE))';
          END IF;

现在,如果您确实需要在每次某些条件为真/假时创建一个新表,并且您想在游标中选择表,请使用参考游标执行以下操作

        create or replace procedure abc(Table_name varchar2 , param_list varchar2 , where_clause varchar2) is
        c_hier sys_refcursor ;
        LV_SQL2 varchar2(2000) ;
        LV_SORT varchar2(2000) ;
        LV_SQL varchar2(2000) ;
        LV_SQL3 varchar2(2000) ;
        begin
        SELECT COUNT(*)
          INTO ln_cnt
          FROM User_Tables
          WHERE table_name = Table_name; -- Use any table here 
          IF ln_cnt = 0 THEN
            EXECUTE IMMEDIATE ' CREATE TABLE '||Table_name||' '||param_list;
            END IF;

          open c_hier for 'SELECT DISTINCT '||param_list||' FROM '||table_name||' '||where_clause; 

         FOR HIER IN C_HIER
          LOOP
            IF C_HIER%ROWCOUNT = 1 THEN
              LV_SQL2         := '(SELECT UOM_ID, NODE_CODE '||HIER.HIER_CODE||' FROM TMP$UOM_COMBO_GEN WHERE UOM_ID='''||P_UOM_ID||''' AND HIER_CODE='''||HIER.HIER_CODE||''')'||HIER.HIER_CODE;
              LV_SORT         := ' ORDER BY '||HIER.HIER_CODE||'';
              LV_SQL          := 'SELECT * FROM ' || LV_SQL2;
            ELSE
              LV_SQL3 := ' LEFT OUTER JOIN(SELECT NODE_CODE '||HIER.HIER_CODE||' FROM TMP$UOM_COMBO_GEN WHERE UOM_ID='''||P_UOM_ID||''' AND HIER_CODE='''||HIER.HIER_CODE||''')'||HIER.HIER_CODE ||' ON 1=1';
              LV_SORT := LV_SORT||','||HIER.HIER_CODE||'';
              LV_SQL  := LV_SQL || LV_SQL3;
            END IF;
          END LOOP;

【讨论】:

以上是关于程序主体内的光标的主要内容,如果未能解决你的问题,请参考以下文章

如何获取光标在指定窗口内的具体位置

ios11,弹出层内的input框光标错位 键盘弹出时,输入信息,光标一直乱跳

如何更改 UITextView 内的起始光标位置

ios11,弹出层内的input框光标错位

自动滚动到放置在 UITableViewCell 内的 textView 光标在 iOS11 中不起作用

如何检查光标范围内的最大值?