PL/SQL assigning query results to a CLOB

僤鯓⒐⒋嵵緔 提交于 2021-02-10 07:54:30

问题


I have a problem, I am creating an CLOB variable with the contents of a query in oracle to email to users, the problem is that it does email as .csv but with no contents. I can not find the problems:

CREATE OR REPLACE PROCEDURE trackekr(cursor1 IN OUT SYS_REFCURSOR)
AS
    v_connection  UTL_SMTP.connection;
    v_clob        CLOB := EMPTY_CLOB();
    v_len         INTEGER;
    v_index       INTEGER;
 c_mime_boundary CONSTANT VARCHAR2(256) := 'the boundary can be almost anything';

    rec           NUMBER(10, 0) := 0;
    d_id          NUMBER(10, 0) := 0;
    customer      VARCHAR2(20);
    wife          VARCHAR2(20);
    date_rec      DATE;
    special_h     VARCHAR2(20);
    g_amount      NUMBER(10, 0) := 0;
    credit_amount NUMBER(10, 0) := 0;
    a_number      VARCHAR2(20);
    a__name       VARCHAR2(20);
BEGIN
    OPEN cursor1 FOR
        SELECT rec,
               d_id,
               customer,
               wife,
               date_rec,
               special h,
               g_amount
          FROM  (your query here);

    WHILE cursor1%NOTFOUND
    LOOP
        FETCH cursor1
              INTO rec,
                   d_id,
                   customer,
                   wife,
                   date_rec,
                   special_h,
                   g_amount,
                   credit_amount,
                   a_number,
                   a__name;

        v_clob :=
               v_clob
            || rec
            || ','
            || d_id
            || ','
            || customer
            || ','
            || wife
            || ','
            || date_rec
            || ','
            || special_h
            || ','
            || g_amount
            || ','
            || credit_amount
            || ','
            || a_number
            || ','
            || a__name
            || UTL_TCP.crlf;
    END LOOP;

    -- UTL

    v_connection := UTL_SMTP.open_connection(mailhost, 25);  
    SMTP server name or ip address
    UTL_SMTP.helo(v_connection, mail.exchange.mydomain.com);
    UTL_SMTP.mail(v_connection, 'mylogin.Exchange.mydomain.com');
    UTL_SMTP.rcpt(v_connection, 'mylogin.Exchange.mydomain.com'); 
    UTL_SMTP.open_data(v_connection);

    UTL_SMTP.write_data(v_connection, 'From: ' || 'mylogin.Exchange.mydomain.com' || UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'To: ' || 'mylogin.Exchange.mydomain.com' || UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'Subject: test subject' || UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'MIME-Version: 1.0' || UTL_TCP.crlf);

    UTL_SMTP.write_data(
        v_connection,
        'Content-Type: multipart/mixed; boundary="' || c_mime_boundary || '"' || UTL_TCP.crlf
    );
    UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
    UTL_SMTP.write_data(
        v_connection,
        'This is a multi-part message in MIME format.' || UTL_TCP.crlf
    );

    UTL_SMTP.write_data(v_connection, '--' || c_mime_boundary || UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, 'Content-Type: text/plain' || UTL_TCP.crlf);

    -- Set up attachment header
    UTL_SMTP.write_data(
        v_connection,
        'Content-Disposition: attachment; filename="' || 'FIRSTFILE.csv' || '"' || UTL_TCP.crlf
    );
    UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);

    -- Write attachment contents

    v_len := DBMS_LOB.getlength(v_clob);
    v_index := 1;

    WHILE v_index <= v_len
    LOOP
        UTL_SMTP.write_data(v_connection, DBMS_LOB.SUBSTR(v_clob, 32000, v_index));
        v_index := v_index + 32000;
    END LOOP;

    -- End attachment
    UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
    UTL_SMTP.write_data(v_connection, '--' || c_mime_boundary || '--' || UTL_TCP.crlf);

    UTL_SMTP.close_data(v_connection);
    UTL_SMTP.quit(v_connection);
END; 

As I said, it emails a .csv file but empty.


回答1:


Note this part in your code:

WHILE cursor1%NOTFOUND

Your loop will never be executed for non-empty dataset. Use this instead:

WHILE cursor1%FOUND

Or even better use implicit cursor:

FOR cursor1 in
        (SELECT rec,
               d_id,
               customer,
               wife,
               date_rec,
               special_h,
               g_amount,
               credit_amount,
               a_number,
               a__name
          FROM  (your query here))
LOOP
v_clob :=
               v_clob
            || cursor1.rec
            || ','
            || cursor1.d_id
            || ','
            || cursor1.customer
            || ','
            || cursor1.wife
            || ','
            || cursor1.date_rec
            || ','
            || cursor1.special_h
            || ','
            || cursor1.g_amount
            || ','
            || cursor1.credit_amount
            || ','
            || cursor1.a_number
            || ','
            || cursor1.a__name
            || UTL_TCP.crlf;
END LOOP;



回答2:


The example below, write the query to clob and then to blob to put in a file

You just need to use the first step, until the line 87

SELECT dbms_lob.getlength(l_clob) INTO len FROM dual;

DECLARE
  l_output      utl_file.file_type;
  c1            INTEGER DEFAULT dbms_sql.open_cursor;
  l_columnvalue VARCHAR2(4000);
  l_status      INTEGER;
  l_colcnt      NUMBER := 0;
  l_separator   VARCHAR2(30);
  l_desctbl     dbms_sql.desc_tab;
  l_flag        NUMBER;
  l_dir         VARCHAR2(50);
  l_arq         VARCHAR2(100);
  l_clob        CLOB;
  l_query       VARCHAR2(50);
  vstart        NUMBER := 1;
  bytelen       NUMBER := 32000;
  len           NUMBER;
  my_vr         RAW(32000);
  x             NUMBER;
  dest_offset   INTEGER;
  src_offset    INTEGER;
  blob_csid     NUMBER;
  lang_context  INTEGER;
  blb           BLOB;
  warning       INTEGER;
BEGIN
  l_query := 'select * from safx07_v  where rownum <=100';

  SELECT 'safx07' || to_char(SYSDATE, 'DDMMYY_HH24MISS') || '.txt'
    INTO l_arq
    FROM dual;

  l_dir := 'ORACLE_EXP';

  l_output := utl_file.fopen(l_dir, l_arq, 'wb');
  --l_output := utl_file.fopen('ORACLE_EXP', 'filename.txt', 'wb', 32760);
  --l_separator := separator;

  IF l_separator = '' OR l_separator IS NULL THEN
    l_separator := chr(9);
  END IF;

  dbms_sql.parse(c1, l_query, dbms_sql.native);
  dbms_sql.describe_columns(c1, l_colcnt, l_desctbl);

  dbms_lob.createtemporary(l_clob, TRUE,DBMS_LOB.call);

  /*  

  FOR cr IN (l_query) LOOP

    dbms_lob.writeappend(l_clob, length(cr.txt), cr.txt);

  END LOOP;*/

  FOR i IN 1 .. l_colcnt LOOP
    dbms_output.put_line(l_desctbl(i).col_name || l_separator);
    dbms_output.put_line(length(l_desctbl(i).col_name || l_separator));
    /*    utl_file.put(l_output, l_desctbl(i).col_name || l_separator);
    dbms_sql.define_column(c1, i, l_columnvalue, 4000);*/

    dbms_lob.writeappend(l_clob,
                         length(l_desctbl(i).col_name || l_separator),
                         l_desctbl(i).col_name || l_separator);
    dbms_sql.define_column(c1, i, l_columnvalue, 4000);

  END LOOP;

  --utl_file.new_line(l_output);

  l_status := dbms_sql.execute(c1);

  dbms_lob.writeappend(l_clob, length(chr(10)), chr(10));

  WHILE (dbms_sql.fetch_rows(c1) > 0) LOOP
    FOR i IN 1 .. l_colcnt LOOP
      /*      dbms_sql.column_value(c1, i, l_columnvalue);
      utl_file.put(l_output, l_columnvalue || l_separator);*/
      dbms_sql.column_value(c1, i, l_columnvalue);
      dbms_lob.writeappend(l_clob, length(l_columnvalue || l_separator),
                           l_columnvalue || l_separator);
    END LOOP;
    dbms_lob.writeappend(l_clob, length(chr(10)), chr(10));
  END LOOP;

  --utl_file.fclose(l_output);

  SELECT dbms_lob.getlength(l_clob) INTO len FROM dual;

  dbms_lob.createtemporary(blb, FALSE);
  dest_offset  := 1;
  src_offset   := 1;
  lang_context := 0;

  -- convert to a BLOB here:
  dbms_lob.converttoblob(blb, l_clob, dbms_lob.getlength(l_clob),
                         dest_offset, src_offset, 0, lang_context, warning);

  -- if small enough for a single write
  IF len < 32760 THEN
    utl_file.put_raw(l_output, blb);
    utl_file.fflush(l_output);
  ELSE
    -- write in pieces
    vstart := 1;
    WHILE vstart < len AND bytelen > 0 LOOP
      dbms_lob.read(blb, bytelen, vstart, my_vr);

      utl_file.put_raw(l_output, my_vr);
      utl_file.fflush(l_output);

      -- set the start position for the next cut
      vstart := vstart + bytelen;

      -- set the end position if less than 32000 bytes
      x := x - bytelen;
      IF x < 32000 THEN
        bytelen := x;
      END IF;
    END LOOP;
  END IF;
  dbms_sql.close_cursor(c1);
  utl_file.fclose(l_output);

EXCEPTION
  WHEN OTHERS THEN
    dbms_sql.close_cursor(c1);
    utl_file.fclose(l_output);
    RAISE;
END;


来源:https://stackoverflow.com/questions/20365006/pl-sql-assigning-query-results-to-a-clob

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!