【问题标题】:Dynamic SQL LOOP动态 SQL 循环
【发布时间】:2014-01-13 11:55:22
【问题描述】:

动态 SQL 不是我的朋友,基本上我的想法是我可以使用带有“p_in_table”参数的过程来获取表中包含的行数。

CREATE OR REPLACE PROCEDURE how_many_rows(p_in_table VARCHAR2)
IS
  TYPE cur_cur IS REF CURSOR;
  v_cur_cur  cur_cur;
  v_rowcount NUMBER(28);
  v_cur_txt  VARCHAR2(299);    
  BEGIN
    v_cur_txt := 'SELECT * FROM ' || p_in_table;

    OPEN v_cur_cur FOR v_cur_txt;

    LOOP
      v_rowcount := v_cur_cur%ROWCOUNT;
      EXIT WHEN v_cur_cur%NOTFOUND;
    END LOOP;

    CLOSE v_cur_cur;

    dbms_output.put_line(v_rowcount);
  END;

如果有人能告诉我我做错了什么,我会感激吗?

【问题讨论】:

  • 使用select count(*),你的工作效率非常低。
  • “SELECT COUNT(*)”无疑是合理的解决方案,虽然我也想仔细研究一下 LOOP 问题,只是为了让自己变得更好。
  • 这是从表中获取计数的最低效的方法。听从马特的建议。
  • 根据它的馈送方式,您对 SQL 注入非常开放。阻止这种情况的最简单方法是通过检查 sysinfo 表(使用正常的准备好的语句)来验证 p_in_table 是否包含表名,如果找不到则抛出相关的错误代码。您需要考虑表名何时被转义(大小写等)以及何时没有被转义的情况;忽略其他所有内容(也就是说,不要担心解决所有 Unicode 恶作剧 - 如果有技巧,您可能应该说“未找到” - 大多数表名将在 ASCII 内)。
  • 谢谢,当我们开始讨论这篇文章时,我想知道,缺少的“FETCH INTO”确实解决了这个问题,同时使用与“p_in_table”相同的表,并且在v_row ??%ROWTPYE,但它会以某种方式使 v_row 声明也动态吗?

标签: sql oracle plsql


【解决方案1】:

问题是你没有遍历游标 - 没有 fetch 语句或类似的东西,所以,基本上,你有一个无限循环。为避免这种情况,您需要执行以下操作:

CREATE OR REPLACE PROCEDURE how_many_rows
   (p_in_table VARCHAR2) IS
   TYPE cur_cur IS REF CURSOR;
   v_cur_cur cur_cur;
   v_rowcount NUMBER(28);
   v_cur_txt VARCHAR2(299);
   v_row SOME_TABLE%ROWTYPE; --add row variable
BEGIN
   v_cur_txt := 'SELECT * FROM '|| p_in_table;

OPEN v_cur_cur FOR v_cur_txt;
   LOOP
      v_rowcount := v_cur_cur%ROWCOUNT;
      FETCH v_cur_cur INTO v_row; --fetch a row in it
         EXIT WHEN v_cur_cur%NOTFOUND;
   END LOOP;
CLOSE v_cur_cur;

DBMS_OUTPUT.PUT_LINE(v_rowcount);
END;

但是,如您所见,要做到这一点,您需要知道您要查询的表是什么,因此这不是一般的解决方案。也许有一个解决方法,但我建议您使用更简单有效的方法,例如使用 EXECUTE IMMEDIATE:

CREATE OR REPLACE PROCEDURE HOW_MANY_ROWS(p_in_table VARCHAR2)
       IS
v_tmp NUMBER;
BEGIN

EXECUTE IMMEDIATE 'SELECT COUNT(1) FROM ' || p_in_table INTO v_tmp;
DBMS_OUTPUT.PUT_LINE(v_tmp);

END;

好的,我考虑了如何使用您的方式来实现这一点,这就是我最终得到的结果 - 只需从您的表中获取 ROWNUM,每个表都有它并且您知道它的类型 - NUMBER。所以这个过程在一般情况下可以工作:

CREATE OR REPLACE PROCEDURE how_many_rows
   (p_in_table VARCHAR2) IS
   TYPE cur_cur IS REF CURSOR;
   v_cur_cur cur_cur;
   v_rowcount NUMBER(28);
   v_cur_txt VARCHAR2(299);
   v_row NUMBER; --add rownum variable
BEGIN
   v_cur_txt := 'SELECT ROWNUM FROM '|| p_in_table; --select only rownum from target table

OPEN v_cur_cur FOR v_cur_txt;
   LOOP
      v_rowcount := v_cur_cur%ROWCOUNT;
      FETCH v_cur_cur INTO v_row; --fetch rownum in it
         EXIT WHEN v_cur_cur%NOTFOUND;
   END LOOP;
CLOSE v_cur_cur;

DBMS_OUTPUT.PUT_LINE(v_rowcount);
END;

【讨论】:

    猜你喜欢
    • 2020-09-09
    • 2018-02-12
    • 2014-10-04
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    • 2020-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多