1

我刚刚开始学习 PL/SQL。在 stackoverflow 的帖子之后,我编写了一个脚本来搜索 Oracle 中的某个值,如下所示:

DECLARE
  match_count INTEGER;
  v_owner VARCHAR2(255);
  v_search_value NUMBER;
BEGIN
  v_owner:='USERA USERB';
  v_search_value:=4823.0;
  EXECUTE IMMEDIATE
  'INSERT INTO TMP SELECT owner, table_name, column_name FROM all_tab_cols WHERE instr(:1, owner)>0 AND data_type like ''%NUMBER%''' USING v_owner;
  commit;
  FOR t IN (SELECT owner, table_name, column_name FROM TMP) LOOP
    EXECUTE IMMEDIATE 
    'SELECT COUNT(*) FROM '||t.owner||'.'||t.table_name||' WHERE '||t.column_name||'= :1'
    INTO match_count
    USING v_search_value;
    IF match_count > 0 THEN
      EXECUTE IMMEDIATE
      'INSERT INTO RESULT VALUES(:1, :2, :3, :4)'
      USING t.owner, t.table_name, t.column_name, match_count;
      commit;
    END IF;
  END LOOP;
END;

在执行脚本之前已正确创建表 TMP 和 RESULT。但是,当我运行脚本时,我在第 12 行收到 ORA-01788 错误,提示“需要按子句连接”。我想知道为什么代码会导致此错误以及如何更改脚本以正确执行。谢谢!

4

1 回答 1

6

您可能有一个表,其中有一列名为level(正如我不看时弗洛林建议的那样),这是一个保留字

在任何情况下都可能是 - 不仅是level,而是LEVEL,或者Level- 所以要检查你可以这样做:

select owner, table_name, column_name
from all_tab_columns
where upper(column_name) = 'LEVEL';

或者寻找任何正在使用的保留字(尽管这并不总是能找到所有潜在的问题):

select atc.owner, atc.table_name, atc.column_name, vrw.keyword
from all_tab_columns atc
join v$reserved_words vrw on vrw.keyword = upper(atc.column_name);

您可以针对其他地方运行类似的查询all_tablesall_objects查找潜在问题。

如果我运行您的查询的修改版本,它不会打扰TMP表格 - 不确定您为什么想要那个;不使用动态 SQL 进行插入;不提交(这是在一个块中做的一件奇怪的事情——你不需要在每次插入之后都这样做);并且只是为了我的利益只显示匹配项而不需要建立一个results表:

declare
  match_count integer;
  v_owner varchar2(255);
  v_search_value number;
begin
  v_owner := 'USERA USERB';
  v_search_value := 4823.0;
  for t in (
      select owner, table_name, column_name
      from all_tab_cols
      where instr(v_owner, owner) > 0
      and data_type like '%NUMBER%'
    ) loop
    execute immediate 
      'select count(*) from ' || t.owner ||'.'|| t.table_name
        || ' where ' || t.column_name || ' = :1'
      into match_count using v_search_value;
    if match_count > 0 then
--    insert into results values (t.owner, t.table_name,
--      t.column_name, match_count);
      dbms_output.put_line('Matched ' || t.owner ||'.'|| t.table_name
        ||'.'|| t.column_name ||': '|| match_count);
    end if;
  end loop;
end;
/

...这成功完成。如果我添加一个带有level列的表:

create table t42 ("LEVEL" number);

...然后再次运行相同的块然后我也得到:

ORA-01788: CONNECT BY clause required in this query block
ORA-06512: at line 14
01788. 00000 -  "CONNECT BY clause required in this query block"
*Cause:    
*Action:

除了避免在对象名称中使用保留字之外,您还可以通过将所有对象名称括在双引号中来完成这项工作:

    execute immediate 
      'select count(*) from "' || t.owner ||'"."'|| t.table_name
        || '" where "' || t.column_name || '" = :1'
      into match_count using v_search_value;

这也将处理大小写混合的对象名称,您也应该避免这种情况。

于 2013-02-28T08:44:09.450 回答