5

コンパイラが「PL/SQL: ORA-00942: テーブルまたはビューが存在しません」と報告するため、Oracle コードのこのセクションをコンパイルできません。

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,'XXX@XXXXXX.com');
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;
4

3 に答える 3

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 ステートメントでカーソルを返すことはできないと思います。このドキュメント ページの2 番目の段落は、そうではないことを示しているようです。いずれにせよ、それは必要ありません。ただ OPEN - FOR 構文を使用してください。

于 2012-07-18T23:19:47.493 に答える
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,'XXX@XXXXXX.com');
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;
于 2012-07-19T09:06:45.327 に答える
0

このようなSQLステートメントに変数を渡す唯一の方法は、動的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

カーソルができたので、コンテンツをフェッチし、カウントをループして、他のすべてを実行します

于 2012-07-18T21:36:12.453 に答える