2013-06-03 41 views
0

我已經創建了下面的PL/SQL存儲過程來搜索整個Oracle11g數據庫中的字符串(srchstr)並返回找到該字符串的表和列到名爲VALUESEARCHRESULTS的表格。Oracle:在整個數據庫中搜索字符串:錯誤ORA-00911

作爲用戶,該過程在Oracle XE中通過SQL Developer成功運行。然而,當嘗試在Oracle11g中運行它作爲用戶SYS的架構ABC,我收到以下錯誤:

ORA-00911:無效字符 原因:標識不得與字母和數字以外的任何ASCII字符開始。 $#_也可以在第一個字符之後。用雙引號括起來的標識符可以包含除雙引號以外的任何字符。替代引號(q「#...#」)不能使用空格,製表符或回車符作爲分隔符。對於所有其他上下文,請參閱「SQL語言參考手冊」。

有誰知道這可能是爲什麼?請參閱下面的代碼。

CREATE OR REPLACE PROCEDURE ABC.FIND_STRING(p_str IN VARCHAR2) authid current_user is 
    l_query clob; 
    srchstr varchar2(30) := ''; 
    r_cname varchar2(30) := ''; 
    l_case  clob; 
    l_runquery boolean; 
    l_tname varchar2(30); 
    l_cname varchar2(30); 
begin 
    dbms_application_info.set_client_info('%' || upper(p_str) || '%'); 

    for x in (select * from user_tables) 
    loop 
     l_query := 'select ''' || x.table_name || ''', $$ 
        from ' || x.table_name || ' 
        where rownum = 1 and (1=0 '; 
     l_case := 'case '; 
     l_runquery := FALSE; 
     for y in (select * 
        from user_tab_columns 
        where table_name = x.table_name 
        and (data_type in('CHAR', 'DATE', 'FLOAT', 'NCHAR', 'NUMBER', 'NVARCHAR2', 'VARCHAR2') 
         or data_type like 'INTERVAL%' or data_type like 'TIMESTAMP%') 
       ) 
     loop 
      l_runquery := TRUE; 
      l_query := l_query || ' or upper(' || y.column_name || 
         ') like userenv(''client_info'') '; 
      l_case := l_case || ' when upper(' || y.column_name || 
        ') like userenv(''client_info'') then ''' || 
        y.column_name || ''''; 
     end loop; 
     if (l_runquery) 
     then 
      l_case := l_case || ' else NULL end'; 
      l_query := replace(l_query, '$$', l_case) || ')'; 
      begin 
       execute immediate l_query into l_tname, l_cname; 
       r_cname := l_cname; 
       dbms_application_info.read_client_info(srchstr); 
       insert into ABC.ValueSearchResults (resulttable, resultcolumn, searchstring) values (x.table_name, r_cname, srchstr); 
       dbms_output.put_line 
       (srchstr || ' found in ' || l_tname || '.' || l_cname); 
      exception 
       when no_data_found then 
        dbms_output.put_line 
        (srchstr || ' has no hits in ' || x.table_name); 
      end; 
      end if; 
     end loop; 
     end; 

EDIT:上述存儲過程編譯沒有錯誤。下面的代碼通過將表中的值傳遞給存儲過程來執行存儲過程。該錯誤顯示何時運行下面的代碼:

BEGIN 
    FOR c IN (SELECT ControlValue FROM ABC.ControlValues) LOOP 
     ABC.FIND_STRING(c.ControlValue); 
    END LOOP; 
END; 
+3

當你處理動態SQL,這是難以置信的幫助登錄時,你會得到一個錯誤,您正在執行特別的SQL語句。如果您可以發佈生成的SQL語句失敗,那麼找出錯誤的位置要容易得多。我的下注是你有一些區分大小寫的標識符,所以你需要用動態SQL語句用雙引號括起你的表和列名。另外,我無法想象爲什麼你想讓用戶在特定的字符串中搜索NUMBER或DATE或TIMESTAMP列 - 這看起來並不合理。 –

+0

謝謝Justin - 我已經更新了我的問題以包含執行存儲過程的代碼。我已經包含NUMBER,DATE和TIMESTAMP,因爲在某些情況下我將搜索數字,日期等。我也會嘗試使用雙引號。 – Alamar

+1

調用存儲過程的代碼並不是那麼有趣。這是你建立一個傳遞給'EXECUTE IMMEDIATE'的SQL語句,你需要登錄和發佈。假如你接受一個字符串作爲參數,你將如何使用這個函數來搜索'DATE'。如果你傳遞一個字符串「2013年3月1日」,你的函數需要知道字符串的格式,並在比較之前調用'to_char(date_column,'Month DD YYYY''')。除非您希望結果根據會話的「NLS_DATE_FORMAT」和「NLS_TIMESTAMP_FORMAT」而變化。 –

回答

0

我發現了一個問題的解決方案,我最初提出。

錯誤原因:未指定模式;只抓取用戶特定的表格。

雖然存儲過程在部署爲用戶ABC時會執行,但在將存儲過程作爲其他ABC用戶運行時產生的錯誤。它出現了多個模式中存在的相同表名。因此,添加OWNER變量指定了與表名相關聯的模式並消除了錯誤。

此外,該過程最初是在搜索USER_TABLES。這將結果限制爲僅當前模式的表格。通過用DBA_TABLES替換USER_TABLES,存儲過程的搜索遍歷數據庫的所有表。

請參閱以下更正後的代碼:

CREATE OR REPLACE 
PROCEDURE FIND_STRING(
    p_str IN VARCHAR2) authid current_user 
IS 
    l_query CLOB; 
    srchstr VARCHAR2(100) := ''; 
    r_cname VARCHAR2(100) := ''; 
    l_case CLOB; 
    l_runquery BOOLEAN; 
    l_tname VARCHAR2(100); 
    l_cname VARCHAR2(100); 
BEGIN 
    dbms_application_info.set_client_info('%' || upper(p_str) || '%'); 
    FOR x IN 
    (SELECT * 
    FROM dba_tables 
    WHERE table_name <> 'CONTROLVALUES' 
    AND table_name  <> 'VALUESEARCHRESULTS' 
    AND tablespace_name <> 'SYSTEM' 
    AND tablespace_name <> 'SYSAUX' 
    AND tablespace_name <> 'TEMP' 
    AND tablespace_name <> 'UNDOTBS1' 
) 
    LOOP 
    l_query := 'select ''' || x.owner || '.' || x.table_name || ''', $$       
from ' || x.owner || '.' || x.table_name || '       
where rownum = 1 and (1=0 '; 
    l_case  := 'case '; 
    l_runquery := FALSE; 
    FOR y IN 
    (SELECT * 
    FROM dba_tab_columns 
    WHERE table_name = x.table_name 
    AND owner  = x.owner 
    AND (data_type IN ('CHAR', 'DATE', 'FLOAT', 'NCHAR', 'NUMBER', 'NVARCHAR2', 'VARCHAR2') 
    OR data_type LIKE 'INTERVAL%' 
    OR data_type LIKE 'TIMESTAMP%') 
    ) 
    LOOP 
     l_runquery := TRUE; 
     l_query := l_query || ' or upper(' || y.column_name || ') like userenv (''client_info'') '; 
     l_case  := l_case || ' when upper(' || y.column_name || ') like userenv (''client_info'') then ''' || y.column_name || ''''; 
    END LOOP; 
    IF (l_runquery) THEN 
     l_case := l_case || ' else NULL end'; 
     l_query := REPLACE(l_query, '$$', l_case) || ')'; 
     BEGIN 
     EXECUTE immediate l_query INTO l_tname, l_cname; 
     r_cname := l_cname; 
     dbms_application_info.read_client_info(srchstr); 
     INSERT 
     INTO VALUESEARCHRESULTS 
      (
      resulttable, 
      resultcolumn, 
      searchstring 
     ) 
      VALUES 
      (
      x.table_name, 
      r_cname, 
      srchstr 
     ); 
     dbms_output.put_line (srchstr || ' found in ' || l_tname || '.' || l_cname); 
     EXCEPTION 
     WHEN no_data_found THEN 
     dbms_output.put_line (srchstr || ' has no hits in ' || x.owner || '.' || x.table_name); 
     END; 
    END IF; 
    END LOOP; 
END; 
相關問題