2012-07-18 5 views
5

コンパイラが「PL/SQL:ORA-00942:table」と報告するので、このOracleコードの項を遵守することはできませんビューが存在しません "Oracle pl/sql電子メール送信でForループを実行するときにテーブル名に変数を使用する方法

Oracleテーブルが存在しますが、このプロシージャは" Order_ID "パラメータに基づいてForループプロシージャにテーブル名を渡す必要があります。テーブルが存在するスキーマ内で作業しているため、スキーマ名には対応していません。

例:TEMP_TBL_123がデータベースに存在し、123のorder_IDを渡すと、変数TMP_TBL_NMを使用してテーブル名 "TEMP_TBL_123"を保持しようとしています。

...................................... ...

CREATE OR REPLACE PROCEDURE EMAIL_DEPT_BLAST_TEST (SUBJECT VARCHAR2,MAIL_FROM VARCHAR2, MAIL_TO VARCHAR2, 
               L_MESSAGE VARCHAR2, L_MESSAGE2 VARCHAR2, ORDER_ID NUMBER) 
IS 
MAIL_HOST VARCHAR2(30):='XX.XX.XX.XX'; 
MAIL_CONN UTL_SMTP.CONNECTION; 
TMP_TBL_NM VARCHAR2(30); 

BEGIN 

TMP_TBL_NM := 'TEMP_TBL_' || ORDER_ID; 

MAIL_CONN := UTL_SMTP.OPEN_CONNECTION(MAIL_HOST, 25); 
UTL_SMTP.HELO(MAIL_CONN, MAIL_HOST); 
UTL_SMTP.MAIL(MAIL_CONN,'[email protected]'); 
UTL_SMTP.RCPT(MAIL_CONN, MAIL_TO); 
UTL_SMTP.OPEN_DATA(MAIL_CONN); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'Date: '||to_char(trunc(SYSDATE))||utl_tcp.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'From: '|| mail_from ||utl_tcp.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'To: '|| mail_to || utl_tcp.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'Subject: '||subject||utl_tcp.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, UTL_TCP.CRLF); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, ''|| L_MESSAGE || UTL_TCP.CRLF); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, UTL_TCP.CRLF); 

UTL_SMTP.WRITE_DATA(MAIL_CONN, 'Order details:' || UTL_TCP.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'Quantity - Location ID - Address' || UTL_TCP.crlf); 

BEGIN 
    FOR I IN (SELECT LOCATION_ID, TRIM(TO_CHAR(COUNT(*),'9,999')) AS QUANTITY FROM TMP_TBL_NM GROUP BY LOCATION_ID) 
    LOOP 
    UTL_SMTP.WRITE_DATA(MAIL_CONN, I.QUANTITY || ' - '); 
    UTL_SMTP.WRITE_DATA(MAIL_CONN, I.LOCATION_ID || ' '); 
    UTL_SMTP.WRITE_DATA(MAIL_CONN,UTL_TCP.CRLF); 
    END LOOP; 
END; 

UTL_SMTP.WRITE_DATA(MAIL_CONN, L_MESSAGE2 || UTL_TCP.CRLF); 

UTL_SMTP.WRITE_DATA(MAIL_CONN,UTL_TCP.CRLF); 
UTL_SMTP.CLOSE_DATA(MAIL_CONN); 
UTL_SMTP.QUIT(MAIL_CONN); 

END SCT_CNTS_EMAIL_DEPT_BLAST_TEST; 

答えて

0

このようなSQL文に変数を渡すための唯一の方法は、dynamic sqlとしてクエリを実行することです。

あなたのコードのようなものかもしれない:私はジョンのを作る多くの幸運を持っていなかった、今あなたがカーソルを持っていることを

DECLARE 
    query_output SYS_REFCURSOR; 
    query_statement VARCHAR2(1000); 
BEGIN 
    query_statement := 'SELECT LOCATION_ID, TRIM(TO_CHAR(COUNT(*),'9,999')) AS QUANTITY FROM ' || TMP_TBL_NM || ' GROUP BY LOCATION_ID'; 
    execute immediate query_statement using out query_output; 
    .... 
END 

内容をフェッチし、カウント数をループし、他のすべて

+2

"変数を渡す唯一の方法は..動的SQLになります。"本当にそうではありません。文字列や数値などのリテラル値を置く可能性のある場所であれば、PL/SQL変数をインラインSQL文に埋め込むことができます。動的SQLを使用しないとできないことは、テーブル名やカラム名などの* identifer *の代わりに変数を使用することです。これは、変数値がバインドされる前に発生するSQL文の解析時に、識別子名を認識する必要があるためです。 –

5

を行います例の仕事。

DECLARE 
    C SYS_REFCURSOR; 
    stmt VARCHAR2(1000); 
    tmp_tbl_nm VARCHAR2(64) := 'USER_TABLES'; 
    the_name VARCHAR2(64); 
BEGIN 
    stmt := 'SELECT table_name FROM ' || TMP_TBL_NM || ' ORDER BY 1'; 
    OPEN C FOR stmt; 
    LOOP 
     FETCH C INTO the_name; 
     EXIT WHEN C%NOTFOUND; 
     dbms_output.put_line(the_name); 
    END LOOP; 
END; 
/
CONTINENT 
COUNTRY 
COUNTRYINFOIMPORT 
COUNTRY_LANGUAGE 
GEONAME 
LANGUAGE 

PL/SQL procedure successfully completed. 

SQL> 

EXECUTE IMMEDIATE文でカーソルを返すことはできません。 This documentation page,第2段落は、そうでないと思われる。いずれにしても、OPEN-FOR構文を使用するだけで、必要はありません。

1

PL/SQL:ORA-00942を取得する理由は、元のコードでコンパイラが「TMP_TBL_NM」という表を検索しているためです。これはスキーマには存在せず、PL/SQL内の表の名前を保持する変数です。

私は以前の答えを適応させる自由を取って、少しの動的SQLを使って答えのバリエーションを作り出しました。

CREATE OR REPLACE PROCEDURE EMAIL_DEPT_BLAST_TEST (SUBJECT VARCHAR2,MAIL_FROM VARCHAR2, MAIL_TO VARCHAR2, 
               L_MESSAGE VARCHAR2, L_MESSAGE2 VARCHAR2, ORDER_ID NUMBER) 
IS 
MAIL_HOST VARCHAR2(30):='XX.XX.XX.XX'; 
MAIL_CONN UTL_SMTP.CONNECTION; 
TMP_TBL_NM VARCHAR2(30); 

BEGIN 

TMP_TBL_NM := 'TEMP_TBL_' || ORDER_ID; 

MAIL_CONN := UTL_SMTP.OPEN_CONNECTION(MAIL_HOST, 25); 
UTL_SMTP.HELO(MAIL_CONN, MAIL_HOST); 
UTL_SMTP.MAIL(MAIL_CONN,'[email protected]'); 
UTL_SMTP.RCPT(MAIL_CONN, MAIL_TO); 
UTL_SMTP.OPEN_DATA(MAIL_CONN); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'Date: '||to_char(trunc(SYSDATE))||utl_tcp.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'From: '|| mail_from ||utl_tcp.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'To: '|| mail_to || utl_tcp.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'Subject: '||subject||utl_tcp.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, UTL_TCP.CRLF); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, ''|| L_MESSAGE || UTL_TCP.CRLF); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, UTL_TCP.CRLF); 

UTL_SMTP.WRITE_DATA(MAIL_CONN, 'Order details:' || UTL_TCP.crlf); 
UTL_SMTP.WRITE_DATA(MAIL_CONN, 'Quantity - Location ID - Address' || UTL_TCP.crlf); 

TYPE ItemRec IS RECORD (
loc_id NUMBER, 
qty_cnt NUMBER); 

TYPE ItemSet IS TABLE OF ItemRec; 
all_items ItemSet; 

BEGIN 

    stmt := 'SELECT LOCATION_ID, TRIM(TO_CHAR(COUNT(*),'9,999')) AS QUANTITY FROM '||TMP_TBL_NM ||' GROUP BY LOCATION_ID'; 
    EXECUTE IMMEDIATE stmt 
    BULK COLLECT 
    INTO all_items; 

    FOR i IN all_items.FIRST..all_items.LAST 
    LOOP 
     UTL_SMTP.WRITE_DATA(MAIL_CONN, I.QUANTITY || ' - '); 
     UTL_SMTP.WRITE_DATA(MAIL_CONN, I.LOCATION_ID || ' '); 
     UTL_SMTP.WRITE_DATA(MAIL_CONN,UTL_TCP.CRLF); 
    END LOOP; 
END; 

UTL_SMTP.WRITE_DATA(MAIL_CONN, L_MESSAGE2 || UTL_TCP.CRLF); 

UTL_SMTP.WRITE_DATA(MAIL_CONN,UTL_TCP.CRLF); 
UTL_SMTP.CLOSE_DATA(MAIL_CONN); 
UTL_SMTP.QUIT(MAIL_CONN); 

END SCT_CNTS_EMAIL_DEPT_BLAST_TEST; 
関連する問題