1

我的 plsql 代码有问题并尝试了几乎所有方法。现在我失去了解决我的问题的想法和力量:)

情况是我想在所有表模式中搜索分配给变量 v_ss 的特定字符串并将其打印到 DBMS_OUTPUT。我知道这种情况有现成的解决方案,但我想自己编写代码。下面的代码在我的 v_stmt 中给了我一个“表不存在”的错误。我假设这个选择不能识别rec.column_name,但为什么呢?

这是我的代码:

DECLARE
 v_stmt VARCHAR2(1000);
 v_ss VARCHAR2(30) := 'Argentina';

 v_own ALL_TAB_COLUMNS.OWNER%TYPE;
 v_tab_nam ALL_TAB_COLUMNS.TABLE_NAME%TYPE;
 v_col_nam ALL_TAB_COLUMNS.COLUMN_NAME%TYPE;

 CURSOR cur_asc IS
   SELECT t.owner, t.table_name, t.column_name
   FROM SYS.ALL_TAB_COLUMNS t
   WHERE t.OWNER LIKE 'HR'
     AND t.DATA_TYPE LIKE 'VARCHAR2';


BEGIN
  FOR rec IN cur_asc LOOP
    v_stmt := 'SELECT rec.owner, rec.table_name, rec.column_name FROM rec.table_name WHERE rec.column_name LIKE :1';
    EXECUTE IMMEDIATE v_stmt INTO v_own, v_tab_nam, v_col_nam USING v_ss;
    DBMS_OUTPUT.put_line(v_own || ':' || v_tab_nam || ':' || v_col_nam);
  END LOOP;


END;
/

Error report -
ORA-00942: table or view does not exist
ORA-06512: at line 19
00942. 00000 -  "table or view does not exist"
*Cause:    
*Action:

你能给我解释一下我的错误以及如何修复它吗?提前致谢

4

3 回答 3

1

动态语句在看不到您的 PL/SQL 变量的上下文中执行,因此当它运行时rec.table_name等被解释为 SQL 级对象 - 这些对象不存在。

您必须将变量值连接到fromandwhere子句的动态语句中;您可以在选择列表中执行相同的操作(尽管它们需要包含在转义的单引号中,因为它们是字符串),或者在那里使用绑定变量:

v_stmt := 'SELECT :owner, :table_name, :column_name FROM '
  || rec.table_name || ' WHERE ' || rec.column_name || ' LIKE :ss';
EXECUTE IMMEDIATE v_stmt INTO v_own, v_tab_nam, v_col_nam
USING rec.owner, rec.table_name, rec.column_name, v_ss;

您不能将绑定变量用于对象标识符,因此需要对这些部分进行串联。

除非您以 HR 用户身份运行它,在这种情况下您可以使用user_tables而不是all_tables,您还需要在查询中指定模式(正如 Tony 和 Lalit 提到的);硬编码 HR 或使用查询的所有者:

v_stmt := 'SELECT :owner, :table_name, :column_name FROM '
  || rec.owner || '.' || rec.table_name
  || ' WHERE ' || rec.column_name || ' LIKE :ss';

但是,对于所有不包含恰好一个匹配值的表,这将出错 - 如果动态选择获得零行或多行。但这是一个单独的问题。

于 2016-02-19T11:12:06.783 回答
1

这里有2个问题:

  1. 您需要将表名和列名连接到动态 SQL 中,因为 'SELECT rec.owner...' 正在尝试owner从具有 alias 的表中选择一个调用的列rec,它不引用您的 for 循环记录。
  2. 由于表中可能没有匹配的行或匹配的行很多,所以不能使用select into,需要使用游标。

尝试这个:

DECLARE
 v_stmt VARCHAR2(1000);
 v_ss VARCHAR2(30) := 'Argentina';

 v_own ALL_TAB_COLUMNS.OWNER%TYPE;
 v_tab_nam ALL_TAB_COLUMNS.TABLE_NAME%TYPE;
 v_col_nam ALL_TAB_COLUMNS.COLUMN_NAME%TYPE;

 CURSOR cur_asc IS
   SELECT t.owner, t.table_name, t.column_name
   FROM ALL_TAB_COLUMNS t
   WHERE t.DATA_TYPE LIKE 'VARCHAR2'
   AND ROWNUM < 10;

 c SYS_REFCURSOR;

BEGIN
  FOR rec IN cur_asc LOOP
    v_stmt := 'SELECT ''' || rec.owner || ''',''' || rec.table_name || ''', ''' || rec.column_name || ''' FROM ' || rec.table_name || ' WHERE ' || rec.column_name || ' LIKE :1';
    OPEN c FOR v_stmt USING v_ss;
    LOOP
      FETCH c INTO v_own, v_tab_nam, v_col_nam;
      EXIT WHEN c%NOTFOUND;
      DBMS_OUTPUT.put_line(v_own || ':' || v_tab_nam || ':' || v_col_nam);
    END LOOP;
    CLOSE c;
  END LOOP;
END;
/
于 2016-02-19T11:13:29.317 回答
1

v_stmt := 'SELECT rec.owner, rec.table_name, rec.column_name FROM rec.table_name WHERE rec.column_name LIKE :1';

  1. 您的动态 sql 语句格式错误。如果您将变量括在单引号之间,那么它们将被视为文字而不是变量。
  2. 您必须在 table_name 之前为模式添加前缀,否则您必须在以HR用户身份连接时运行脚本。
v_stmt := 'SELECT '''||rec.owner||''', '''|| rec.table_name||''', '
                     ||rec.column_name||' FROM '||rec.owner||'。'
                     ||rec.table_name||' WHERE '||rec.column_name||' 喜欢:1';

永远记住,无论何时使用动态语句,始终使用DBMS_OUTPUT来首先验证正在生成的实际 SQL。这是调试动态查询的最佳方式。

  1. 您需要处理NO_DATA_FOUND异常,因为它会为所有与您使用的过滤器不匹配的表抛出错误。
SQL> 声明
  2 v_stmt VARCHAR2(1000);
  3 v_ss VARCHAR2(30) := '阿根廷';
  4 v_own ALL_TAB_COLUMNS.OWNER%TYPE;
  5 v_tab_nam ALL_TAB_COLUMNS.TABLE_NAME%TYPE;
  6 v_col_nam ALL_TAB_COLUMNS.COLUMN_NAME%TYPE;
  7 光标 cur_asc
  8 是
  9 选择 t.owner,
 10 t.table_name,
 11 t.column_name
 12 来自 SYS.ALL_TAB_COLUMNS t
 13 所有者喜欢“HR”的地方
 14 AND t.DATA_TYPE LIKE 'VARCHAR2';
 15 开始
 16 FOR REC IN cur_asc
 17 循环
 18 v_stmt := 'SELECT '''||rec.owner||''', '''|| rec.table_name||''', '
 19 || rec.column_name||' FROM '||rec.owner||'。'
 20 || rec.table_name||' WHERE '||rec.column_name||' 喜欢:1';
 21 开始
 22 立即执行 v_stmt 进入 v_own,
 23 v_tab_nam,
 24 v_col_nam 使用 v_ss;
 25 DBMS_OUTPUT.put_line(v_own || ':' || v_tab_nam || ':' || v_col_nam);
 26 例外
 27 当 NO_DATA_FOUND THEN
 28 空;
 29 结束;
 30 结束循环;
 31 结束;
 32 /
人力资源:国家:阿根廷

PL/SQL 过程成功完成。
于 2016-02-19T11:19:27.487 回答