I have a stored procedure that reads value from table and sends them as CSV file. I wanted the following to be the headers of the CSV file .
'ID ,INPUT_DATE ,PAYER ,AMOUNT ,TYPE ,PAYEE-SORTCODE_&_BANK_ACCOUNT_NO ,ADDITIONAL_REMARKS ,COMMENTS ,ACCOUNT_NUMBER ,POLICY_NUMBER ,DATE_OF_BRANCH_CONFIRMATION ,CONFIRMED_BY ,SHEETUPDATE_DATE ,MAILUPDATE_DATE ,DATE-TIME ,USER_ID ,STATUS '
The procedure reads data from table and adds header and stores in a clob variable . the data looks like this when printed in log before it is added as mail attachment .
But when it is mailed as attachment it doesnt have a header and only has the data
Here is my code :
create or replace PROCEDURE EMAIL_DUMP AS
l_clob2 clob;
l_attach_text2 clob;
l_attach_text_h2 clob;
v_From VARCHAR2(280) := 'abc';
v_Recipient VARCHAR2(280) := 'efg';
v_Subject VARCHAR2(280) := ' Details';
v_Mail_Host VARCHAR2(230) := 'internal';
v_Mail_Conn utl_smtp.Connection;
crlf VARCHAR2 (32767) := chr(13)||chr(10);
c_mime_boundary CONSTANT VARCHAR2 (256) := '¿AAAAA000956¿';
v_index integer;
v_len integer;
FC_SV_STATUS_DESC VARCHAR2(100) := 'open';
Record_id Number ;
Input_date varchar2(100);
Payer varchar2(100);
Amount varchar2(100);
Trans_Type varchar2(100);
Payee varchar2(100);
Remarks varchar2(500);
Comments varchar2(500);
Acc_no varchar2(100);
Policy_no varchar2(100);
Branch_of date ;
Confirmed varchar2(100);
Sheet_update date;
Mail_update date;
Upload_time date;
Upload_id varchar2(100);
CURSOR c2 IS
select FC_CA_RECORD_ID as Record_id,FC_CA_INPUT_DATE as Input_date,FC_CA_PAYER as Payer,FC_CA_AMOUNT as Amount,FC_CA_TYPE as Trans_Type,FC_CA_PAYEE as Payee,FC_CA_ADD_REMARKS as Remarks,FC_CA_COMMENTS as Comments,FC_CA_ACC_NO as Acc_no,FC_CA_POLICY_NO as Policy_no,FC_CA_BRANCHCONF_DATE as Branch_of,FC_CA_CONFIRMED_BY as Confirmed,FC_CA_SHEETUPDATE_DATE as Sheet_update,FC_CA_MAILUPDATE_DATE as Mail_update,FC_CA_UPLOAD_TIME as Upload_time,FC_CA_UPLOAD_ID as Upload_id into Record_id,Input_date,Payer,Amount,Trans_Type,Payee,Remarks,Comments,Acc_no,Policy_no,Branch_of,Confirmed,Sheet_update,Mail_update,Upload_time,Upload_id FROM abc where FC_CA_STATUS =3 ;
BEGIN
l_attach_text_h2 :=
'ID ,INPUT_DATE ,PAYER ,AMOUNT ,TYPE ,PAYEE-SORTCODE_&_BANK_ACCOUNT_NO ,ADDITIONAL_REMARKS ,COMMENTS ,ACCOUNT_NUMBER ,POLICY_NUMBER ,DATE_OF_BRANCH_CONFIRMATION ,CONFIRMED_BY ,SHEETUPDATE_DATE ,MAILUPDATE_DATE ,DATE-TIME ,USER_ID ,STATUS ';
FOR employee_rec2 in c2
LOOP
l_attach_text2 := '"' ||
employee_rec2.Record_id || '","' ||
employee_rec2.Input_date || '","' ||
employee_rec2.Payer || '","' ||
employee_rec2.Amount || '","' ||
employee_rec2.Trans_Type || '","' ||
employee_rec2.Payee || '","' ||
employee_rec2.Remarks || '","' ||
employee_rec2.Comments || '","' ||
employee_rec2.Acc_no || '","' ||
employee_rec2.Policy_no || '","' ||
employee_rec2.Branch_of || '","' ||
employee_rec2.Confirmed || '","' ||
employee_rec2.Sheet_update || '","' ||
employee_rec2.Mail_update || '","' ||
employee_rec2.Upload_time || '","' ||
employee_rec2.Upload_id || '","' ||
FC_SV_STATUS_DESC || '"' ||chr(13);
l_clob2 := l_clob2||chr(10)||l_attach_text2;
END LOOP;
l_clob2 := l_attach_text_h2 ||chr(13)|| l_clob2;
DBMS_OUTPUT.put_line(l_clob2);
v_Mail_Conn := utl_smtp.Open_Connection(v_Mail_Host, 25);
utl_smtp.Helo(v_Mail_Conn, v_Mail_Host);
utl_smtp.Mail(v_Mail_Conn, v_From);
utl_smtp.Rcpt(v_Mail_Conn, v_Recipient);
utl_smtp.OPEN_DATA(v_Mail_Conn);
UTL_SMTP.write_data(v_Mail_Conn, 'From: ' || v_From || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'To: ' || v_Recipient || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'Subject: ' || REPLACE(v_Subject, '[DATE]',TO_CHAR(sysdate,'DD.MM.YYYY')) || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'MIME-Version: 1.0' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'Content-Type: multipart/mixed; boundary="' || c_mime_boundary || '"' || UTL_TCP.crlf);
-- Mail body:
UTL_SMTP.write_data(v_Mail_Conn, '--' || c_mime_boundary || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'Content-Type: text/plain' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, ' Details' || UTL_TCP.crlf);
-- Set up attachment header
UTL_SMTP.write_data(v_Mail_Conn, '--' || c_mime_boundary || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'Content-Type: text/plain' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'Content-Disposition: attachment; filename="' || 'myfile.csv' || '"' || UTL_TCP.crlf);
-- Write attachment contents
v_len := DBMS_LOB.getlength(l_clob2);
v_index := 1;
WHILE v_index <= v_len
LOOP
UTL_SMTP.write_data(v_Mail_Conn, DBMS_LOB.SUBSTR(l_clob2, 32000, v_index));
v_index := v_index + 32000;
END LOOP;
-- End attachment
UTL_SMTP.write_data(v_Mail_Conn, UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, '--' || c_mime_boundary || '--' || UTL_TCP.crlf);
utl_smtp.CLOSE_DATA(v_mail_conn);
utl_smtp.Quit(v_mail_conn);
DBMS_OUTPUT.put_line('mail send completed...');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line ( 'Error raised: '|| DBMS_UTILITY.FORMAT_ERROR_BACKTRACE || ' - '||sqlerrm);
system.intranet_utils.INTRANET_LOG_ERRORS('procedure EmailDump',
system.intranet_utils.INTRANET_GET_ERRMSG, 'Error in EmailDump');
END EMAIL_DUMP;
If I edit the mail attachment part like below ,then I'm able to get a proper CSV file as attachment with hearder and data , but then I am unable to add body message to the mail.
UTL_SMTP.write_data(v_Mail_Conn, 'From: ' || v_From || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'To: ' || v_Recipient || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'Subject: ' || REPLACE(v_Subject, '[DATE]',TO_CHAR(sysdate,'DD.MM.YYYY')) || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'MIME-Version: 1.0' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'Content-Type: multipart/mixed; boundary="' || c_mime_boundary || '"' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'This is a multi-part message in MIME format.' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, '--' || c_mime_boundary || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, 'Content-Type: text/plain' || UTL_TCP.crlf);
-- Set up attachment header
UTL_SMTP.write_data(v_Mail_Conn, 'Content-Disposition: attachment; filename="' || 'CMTL.csv' || '"' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, UTL_TCP.crlf);
-- Write attachment contents
v_len := DBMS_LOB.getlength(l_clob2);
v_index := 1;
WHILE v_index <= v_len
LOOP
UTL_SMTP.write_data(v_Mail_Conn, DBMS_LOB.SUBSTR(l_clob2, 32000, v_index));
v_index := v_index + 32000;
END LOOP;
-- End attachment
UTL_SMTP.write_data(v_Mail_Conn, UTL_TCP.crlf);
UTL_SMTP.write_data(v_Mail_Conn, '--' || c_mime_boundary || '--' || UTL_TCP.crlf);
Can anyone tell me why I cant send a mail with both mail body message and attachment ?
I am new to oracle and here I am trying generate a CSV file from the values from my table and mail it. I am able to generate the csv file but I am unable to add a heading to my file and my date values are being shown as ########. I want the CSV file to be generated as the expected one .
The expected CSV :
The generated CSV :
Here is my code :
l_attach_text_h :=
'RECORD_ID ,INPUTTED DATE ,INPUTTED BY ,BROKER .....
FOR employee_rec in c1
LOOP
l_attach_text := '"' ||
employee_rec.FC_ED_RECORD_ID || '","' ||
employee_rec.FC_ED_UPLOADTIME || '","' ||
employee_rec.FC_ED_USER_ID || '","' ||
employee_rec.FC_ED_BROKER || '","' ||
........
l_clob := l_clob||chr(10)||l_attach_text;
END LOOP;
l_clob := l_attach_text_h ||chr(13)|| l_clob;
DBMS_OUTPUT.put_line(' Dtls processing completed...');
v_Mail_Conn := utl_smtp.Open_Connection(v_Mail_Host, 25);
utl_smtp.Helo(v_Mail_Conn, v_Mail_Host);
utl_smtp.Mail(v_Mail_Conn, v_From);
utl_smtp.Rcpt(v_Mail_Conn, v_Recipient);
utl_smtp.Data(v_Mail_Conn,
'Date: ' || to_char(sysdate, 'Dy, DD Mon YYYY hh24:mi:ss') || crlf ||
'From: ' || v_From || crlf ||
'Subject: '|| v_Subject || crlf ||
'To: ' || v_Recipient || crlf ||
'MIME-Version: 1.0'|| crlf || -- Use MIME mail standard
'Content-Type: multipart/mixed;'|| crlf ||
' boundary="-----SECBOUND"'|| crlf ||
crlf ||
'-------SECBOUND'|| crlf ||
'Content-Type: text/plain;'|| crlf ||
'Content-Transfer_Encoding: 7bit'|| crlf ||
crlf ||
'Please find the following in the attachments :'|| crlf || -- Message body
'Entry details & Entry details'|| crlf ||
crlf ||
'-------SECBOUND'|| crlf ||
'Content-Type: text/plain;'|| crlf ||
' name="Files.csv"'|| crlf ||
'Content-Transfer_Encoding: 8bit'|| crlf ||
'Content-Disposition: attachment;'|| crlf ||
' filename="Files.csv"'|| crlf ||
crlf ||
l_clob || crlf || -- Content of attachment
crlf ||
'-------SECBOUND--' -- End MIME mail
);
utl_smtp.Quit(v_mail_conn);
DBMS_OUTPUT.put_line('mail send completed...');
can anyone help me with this?
As of the heading: create a new comma-separated line which contains all headings, e.g.
SQL> select '"Record ID"' ||','|| '"Inputted Date"' ||','|| '"Inputted By"' as heading from dual;
HEADING
-----------------------------------------
"Record ID","Inputted Date","Inputted By"
SQL>
and include it as the 1st line in the output file.
As of the ###### issue: are you sure it is a problem? What happens when you double-click in between columns B and C in Excel? That operation should adjust column B width so that it matches data width (so I'd expect actual data to be seen afterwards).
this question is a part of this one
limit records in cursor by using a variable
the original question was a 2 part question, 1 part being, IS THERE A BETTER WAY TO DO THIS
i have code that works but it's EXTREMELY slow, about 2 seconds for each record.
so i have a table, NR_POSTAL_ABBR, that has 2 fields and about 400 records
ReplaceWhat ReplaceWith
Ave Avenue
St Street
i want to be able to replace the Address field in another table with the valules from the table above
so if i have an address 123 Main St - it should say 123 Main Street
if i have 123 Main Street - it should stay 123 Main Street, it shouldn't become 123 Main Streetreet
the table with addresses has a few million rows, is there a fast way of doing this?
thank you
So as you asked. My suggestion is go through regular expressions So here is un update code for your case.
Suppose you have a table test with the field address, what you have to do is very simple, create an regular expression that match your requirements.
So: You need to replace every St for Street and Av for Avenue this is what you should do.
update test
set address =
regexp_replace(
regexp_replace(address, 'Av | Av$| Av ', ' Avenue ' ),
'St | St$| St ', ' Street ');
Here is a SQLFiddle example
Explaining the regex:
The regexp_replace replaces a string for another based on a regular expression pattern, see the docs: REGEXP_REPLACE
About the regular expressions you can see it here Regular Expressions Wiki Almost every language follow the POSIX pattern, so once you learn it you will be good.
So I've used to regexp_replace to achieve what you want because you gave two requirements. I will not write about the parameters of the function just the expressions.
At the first expression you have 'Av | Av$| Av ' which means:
PS.: I put the - just to you see the space (so ignore it). SO wont let me put it.
-Av - (with a space at end) = Find every Av with a space after it on the string
-|- (pipe sign) = Equals an or statement
- Av$- = Find all Av with a space before it and when Av is at the end of the string. $
- Av - = Find all Av with a space before and a space after
Then The function replace any of theese ocurrences with the word Avenue. Notice that I put a space before and one after to avoid something like Peer HarborAvenue
The same explanation goes to St string
If you like the regular expressions function you can see more with it here: Oracle Regular Expressions Functions
just posting the automated version based on Jorge's reply, in case someone needs it.
DECLARE
ReplOrder NUMBER;
BEGIN
ReplOrder := 1;
DECLARE
CURSOR getReplsStrng IS
SELECT replacewhat
,replacewith
FROM analyst.NR_POSTAL_ABBR
WHERE ReplaceOrder = ReplOrder;
BEGIN
FOR getInnerRec IN getReplsStrng LOOP
-- DBMS_OUTPUT.put_line('replace what ' || getInnerRec.replacewhat);
-- DBMS_OUTPUT.put_line('Replace Order ' || ReplOrder);
UPDATE NR_TMP_106 tmp
SET NewAddress = LOWER(REGEXP_REPLACE(LOWER(NewAddress)
, '$'
|| getInnerRec.replacewhat
|| ' | '
|| getInnerRec.replacewhat
|| '$| '
|| getInnerRec.replacewhat
|| ' '
,' ' || getInnerRec.replacewith || ' '))
WHERE 1 = 1
AND ( tmp.NewAddress LIKE '%' || CHR(32) || '' || getInnerRec.replacewhat || '' || NULL || '%'
OR tmp.NewAddress LIKE '%' || CHR(32) || '' || getInnerRec.replacewhat || '' || CHR(32) || '%'
OR tmp.NewAddress LIKE '%' || NULL || '' || getInnerRec.replacewhat || '' || CHR(32) || '%');
COMMIT;
END LOOP;
END;
ReplOrder := 2;
DECLARE
CURSOR getReplsStrng IS
SELECT replacewhat
,replacewith
FROM analyst.NR_POSTAL_ABBR
WHERE ReplaceOrder = ReplOrder;
BEGIN
FOR getInnerRec IN getReplsStrng LOOP
-- DBMS_OUTPUT.put_line('replace what ' || getInnerRec.replacewhat);
-- DBMS_OUTPUT.put_line('Replace Order ' || ReplOrder);
UPDATE NR_TMP_106 tmp
SET NewAddress = LOWER(REGEXP_REPLACE(LOWER(NewAddress)
, '$'
|| getInnerRec.replacewhat
|| ' | '
|| getInnerRec.replacewhat
|| '$| '
|| getInnerRec.replacewhat
|| ' '
,' ' || getInnerRec.replacewith || ' '))
WHERE 1 = 1
AND ( tmp.NewAddress LIKE '%' || CHR(32) || '' || getInnerRec.replacewhat || '' || NULL || '%'
OR tmp.NewAddress LIKE '%' || CHR(32) || '' || getInnerRec.replacewhat || '' || CHR(32) || '%'
OR tmp.NewAddress LIKE '%' || NULL || '' || getInnerRec.replacewhat || '' || CHR(32) || '%');
COMMIT;
END LOOP;
END;
END;
I have a file with this:
set linesize 1000
set trimspool on
set trimout on
set pagesize 0
set feedback off
spool result.csv
SELECT process_id || ';' || file_name || ';' || source || ';' || destination || ';' || type || ';' || transfer_name || ';' || message || ';' || message2 || ';' || destination_sub_group
FROM table
WHERE process_id = '12345';
And SQLPLUS is calling it
But this is returning blank spaces, specially message2 field, any idea on how to remove it?
Here is the output:
12345;filename.txt;X;X;4;X;xx = xxxx
Warning: Using insecure memory!
Decoding data....
Secret key is required to read it.
Key for user ID "X"
Error decrypting file '/apps/egs/gen/file_name.txt.pgp'.
;INBOUND
Thanks!
I replaced some values with X.
Here is the output I would like:
12345;filename.txt;X;X;4;X;xx = xxxx Warning: Using insecure memory! Decoding data.... Secret key is required to read it. Key for user ID "X" Error decrypting file /apps/egs/gen/file_name.txt.pgp'.;INBOUND
i fought this problem for days, when i wanted to get the query results into a csv...
set mark csv ON ended up solving the problem in that case... took my for ever to find that command
Try using TRIM to remove trailing and leading spaces and REPLACE to remove linefeeds and carriage returns:
SELECT process_id || ';' || file_name || ';' || source || ';' || destination || ';' || type || ';' || transfer_name || ';' || message || ';' ||
replace(replace(trim(message2),CHR(10),' '),CHR(13),' ') || ';' || destination_sub_group
FROM table WHERE process_id = '12345';
Add the following:
COL the_stuff form a1000
Then add the "the_stuff" column alias to your query:
SELECT process_id .... destination_sub_group the_stuff from ..
This will explicitly allow you some control over how this output is displayed.
Next, to deal with the embedded linefeeds in your output, wrap lot around a TRANSLATE ( ..., CHR(10), '+' )
E.g.
This show data with linefeeds:
SQL> select 'line 1' || chr(10) || 'line2' || chr(10) || 'line 3' txt from dual;
TXT
-------------------
line 1
line2
line 3
Translate to replace the linefeeds with "+":
SQL> select translate ( 'line 1' || chr(10) || 'line2' || chr(10) || 'line 3',
chr(10), '+' ) txt
from dual;
TXT
-------------------
line 1+line2+line 3
SQL>