Home » SQL & PL/SQL » SQL & PL/SQL » New to PL/SQL- How to read from file to write to database table -Tina
New to PL/SQL- How to read from file to write to database table -Tina [message #148803] |
Mon, 28 November 2005 04:47  |
tina_m
Messages: 7 Registered: November 2005
|
Junior Member |
|
|
This is my first question in this forum. Please help.
I want to read from a file say C:\try.txt
C:\try.txt contains data like-
1234|10|0|YYYYYY
12367688|100|200|XXXXX
I would like to read both lines one by one in a cursur and enter the multiple of the 2nd and 3rd part (separated by pipe character "|" ) into a temporary table
Eg-
I want the output as
10*0=0
100*200= 20000
I tried something (see below function), but it gives error while calling this function
CREATE OR REPLACE FUNCTION get_file_line (
check_this_dir_in IN VARCHAR2,
check_this_in IN VARCHAR2
)
RETURN BOOLEAN
IS
checkid UTL_FILE.file_type;
checkline VARCHAR2 (32767);
check_eof BOOLEAN;
--
l_keep_checking BOOLEAN DEFAULT TRUE;
l_identical BOOLEAN DEFAULT FALSE;
PROCEDURE initialize
IS
BEGIN
-- Open file, read-only.
checkid :=
UTL_FILE.fopen (check_this_dir_in
,check_this_in
,'R'-- read_only
,32767--max_linesize
);
END initialize;
PROCEDURE cleanup
IS
BEGIN
UTL_FILE.fclose (checkid);
END cleanup;
PROCEDURE get_next_line_from_file (
file_in IN UTL_FILE.file_type
,line_out OUT VARCHAR2
,eof_out OUT BOOLEAN
)
IS
BEGIN
UTL_FILE.get_line (file_in, line_out);
eof_out := FALSE;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
line_out := NULL;
eof_out := TRUE;
END get_next_line_from_file;
BEGIN
initialize;
WHILE (l_keep_checking)
LOOP
get_next_line_from_file (checkid, checkline, check_eof);
END LOOP;
cleanup;
RETURN l_identical;
EXCEPTION
WHEN OTHERS
THEN
cleanup;
RETURN FALSE;
END get_file_line;
There are 2 errors-
1)
SYS.UTL_FILE must be declared
2)while calling the function-
v := get_file_line ("C:\", "try.txt") gives error as C must be declared
Please let know if I am missing something, or if there is any other code for doing this
[Updated on: Mon, 28 November 2005 06:12] Report message to a moderator
|
|
|
|
Re: New to PL/SQL- How to read from file to write to database table -Tina [message #148816 is a reply to message #148803] |
Mon, 28 November 2005 06:29   |
tina_m
Messages: 7 Registered: November 2005
|
Junior Member |
|
|
thnx. I will check my execute rights.
I again tried it in a different way. there are many errors displayed. Can you pls help on this ..........
A few questions would be-
1) how to call DA.RESULT3_VALUE in cursor.
2)I want to read the file before the cursor -
so how to do a DECLARE, then open file, then read cursor.......
3) Do I write get_line inside the cursor to read first line, insert in table, then read next line, insert in table and so on........
DECLARE
fHandler UTL_FILE.FILE_TYPE;
buf varchar2(4000);
v_service_id number ;--:= value from the file;
v_RESULT3_value NUMBER ;--:= value from the file;
fHandler := UTL_FILE.FOPEN('C:', 'try1.txt', 'r');
--
CURSOR unbilled_usage
IS
SELECT DA.RESULT1_VALUE "Bund_mins", DA.RESULT2_VALUE "Bund_Rate", DA.RESULT3_VALUE "Normal_Rate", PI.PRODUCT_ID
FROM PRODUCT_INSTANCE_HISTORY PI,SERVICE_HISTORY SH, DERIVED_ATTRIBUTE_ARRAY DA, SERVICE_DA_ARRAY SA
WHERE PI.PRODUCT_INSTANCE_ID=SH.BASE_PRODUCT_INSTANCE_ID
AND SH.SERVICE_ID = SA.SERVICE_ID
-- AND SYSDATE BETWEEN SH.EFFECTIVE_START_DATE AND SH.EFFECTIVE_END_DATE
-- AND SYSDATE BETWEEN PI.EFFECTIVE_START_DATE AND PI.EFFECTIVE_END_DATE
AND DA.DERIVED_ATTRIBUTE_ID = 2005589
AND DA.INDEX3_VALUE = 0 -- RATE BAND (FOR DURATION BASED TABLE )
AND DA.INDEX2_VALUE = PI.PRODUCT_ID -- PRODUCT ID
AND DA.INDEX1_VALUE = SA.RESULT1_VALUE -- RATEPLAN
AND SA.INDEX1_VALUE = 6 -- RCONNECT RATEPLAN TYPE
-- AND SYSDATE BETWEEN SA.EFFECTIVE_START_DATE AND SA.EFFECTIVE_END_DATE
AND SA.SERVICE_ID = v_service_id
AND SA.DERIVED_ATTRIBUTE_ID = 1005715;
--UBU_RECORDS unbilled_usage%ROWTYPE
BEGIN
FOR i IN unbilled_usage
LOOP
BEGIN
--OPEN unbilled_usage;
--FETCH unbilled_usage INTO UBU_RECORDS;
FOR i IN unbilled_usage LOOP -- process each row one at a time
UTL_FILE.GET_LINE(fHandler, buf);
dbms_output.put_line('DATA FROM FILE: '||buf);
if i.RESULT3_VALUE is not null then
v_RESULT3_value := to_number(i.RESULT3_VALUE)* v_text_mins_value;
INSERT INTO table_temp VALUES (v_service_id, v_RESULT3_value);
end if;
END LOOP;
UTL_FILE.FCLOSE(fHandler);
COMMIT;
EXCEPTION
WHEN utl_file.invalid_path THEN
raise_application_error(-20000, 'Invalid path. Create directory or set UTL_FILE_DIR.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error '||SQLCODE || " " || SQLERRM);
NULL;
END;
/
One more question not related to this is -
select
instr('1234|10|0|1','|',instr('1234|10|0|1','|'),1)
from dual
--this query returns 5 and the below query returns 8. 5 and 8 are the positions of the first and second "|" character. How can I get the substr between these two i.e. 10.
select
instr('1234|10|0|1','|',instr('1234|10|0|1','|'),2)
from dual
thnx in anticipation
|
|
|
Re: New to PL/SQL- How to read from file to write to database table -Tina [message #148822 is a reply to message #148816] |
Mon, 28 November 2005 07:10   |
 |
Maaher
Messages: 7065 Registered: December 2001
|
Senior Member |
|
|
First a tip: in the sticky (first topic on this page) is a link to the formatter. Use that to format the code. Afterwards you can place your code in CODE tags. The result is this:
(I used Formatter Plus, that filtered out syntax errors as well )
DECLARE
fhandler UTL_FILE.file_type;
buf VARCHAR2 (4000);
v_service_id NUMBER; --:= value from the file;
v_result3_value NUMBER; --:= value from the file;
--
CURSOR unbilled_usage
IS
SELECT da.result1_value Bund_mins
, da.result2_value Bund_Rate
, da.result3_value Normal_Rate
, pi.product_id
FROM product_instance_history pi
, service_history sh
, derived_attribute_array da
, service_da_array sa
WHERE pi.product_instance_id = sh.base_product_instance_id
AND sh.service_id = sa.service_id
AND da.derived_attribute_id = 2005589
AND da.index3_value = 0 -- RATE BAND (FOR DURATION BASED TABLE )
AND da.index2_value = pi.product_id -- PRODUCT ID
AND da.index1_value = sa.result1_value -- RATEPLAN
AND sa.index1_value = 6 -- RCONNECT RATEPLAN TYPE
-- AND SYSDATE BETWEEN SA.EFFECTIVE_START_DATE AND SA.EFFECTIVE_END_DATE
AND sa.service_id = v_service_id
AND sa.derived_attribute_id = 1005715;
--UBU_RECORDS unbilled_usage%ROWTYPE
BEGIN
fhandler := UTL_FILE.fopen ('C:', 'try1.txt', 'r');
FOR i IN unbilled_usage
LOOP -- process each row one at a time
UTL_FILE.get_line (fhandler, buf);
DBMS_OUTPUT.put_line ('DATA FROM FILE: ' || buf);
IF i.result3_value IS NOT NULL
THEN
v_result3_value := TO_NUMBER (i.result3_value)
* v_text_mins_value;
INSERT INTO table_temp
VALUES (v_service_id, v_result3_value);
END IF;
END LOOP;
UTL_FILE.fclose (fhandler);
COMMIT;
EXCEPTION
WHEN UTL_FILE.invalid_path
THEN
raise_application_error
(-20000
, 'Invalid path. Create directory or set UTL_FILE_DIR.'
);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('Error :' || SQLERRM);
END;
/
Looking at your code I see the following:
- The assignment of fhandler should be placed in the execution section (after the begin)
- Your loop is double. Is this on purpose.
- A Begin without an END? Is this begin on purpose?
- SQLERRM contains already the SQLCODE, it's not necessary to double it. Look at the example below:
SQL> BEGIN
2 RAISE VALUE_ERROR;
3 EXCEPTION
4 WHEN OTHERS THEN
5 dbms_output.put_line('Error :'||SQLCODE||': '||SQLERRM);
6 END;
7 /
Error :-6502: ORA-06502: PL/SQL: numeric or value error
PL/SQL procedure successfully completed.
SQL> ed
Wrote file afiedt.buf
1 BEGIN
2 RAISE VALUE_ERROR;
3 EXCEPTION
4 WHEN OTHERS THEN
5 dbms_output.put_line('Error: '||SQLERRM);
6* END;
SQL> /
Error: ORA-06502: PL/SQL: numeric or value error
PL/SQL procedure successfully completed.
>> 1) how to call DA.RESULT3_VALUE in cursor.
You have an alias for your columns, use that. I'd loose the double quotes, by the way. In your case, it would be Normal_Rate instead of result3_value.
>> 2)I want to read the file before the cursor -
You can buffer the lines in a PL/SQL table.
- open the file
- read each line into a record of a PL/SQL table.
- close the file when you're at the end.
Afterwards you can compare the content of your PL/SQL table with the database table.
>> 3) Do I write get_line inside the cursor to read first line, insert in table, then read next line, insert in table and so on........
I don't get this one. Sorry.
>> One more question not related to this is -
SQL> select SUBSTR(thedata
2 ,instr(thedata,'|')+1
3 , instr(thedata,'|',1,2) - instr(thedata,'|') - 1
4 )x
5 from ( select '1234|10|0|1' thedata
6 from dual
7 ) x
8 /
X
--
10 Check the manuals for an explanation about substr and instr. A link to those are in the sticky.
Basically it comes down to this:
you read from the position AFTER the first pipe sign and for a length between the first two pipe signs.
MHE
|
|
|
|
Re: New to PL/SQL- How to read from file to write to database table -Tina [message #148944 is a reply to message #148901] |
Tue, 29 November 2005 03:07   |
tina_m
Messages: 7 Registered: November 2005
|
Junior Member |
|
|
Now everything seems ok to me, but, few errors found nonetheless. Please guide. Also please let know what my mistakes were.
CREATE OR REPLACE Procedure Update_RConnect_usage( filename IN VARCHAR2)
IS
--DECLARE
fhandler UTL_FILE.file_type;
file_dir VARCHAR2(100) := '/temp';
buf VARCHAR2 (4000);
v_service_id NUMBER; --:= value from the file;
v_result3_value NUMBER; --:= value from the file;
v_total_usage NUMBER; -- value (v_result3_value * i.Normal_rate from table)
Invalid_service_id EXCEPTION;
--
BEGIN
fhandler := UTL_FILE.fopen (file_dir, filename, 'R');
IF LENGTH(buf) = 0 THEN
dbms_output.put_line('No Data in file' || filename);
End IF;
-- UTL_FILE.get_line (fhandler, buf);
LOOP
BEGIN
UTL_FILE.get_line (fhandler, buf);
v_service_id := Trim(SUBSTR(buf,1,INSTR(buf,',',1,1)-1));
v_result3_value := Trim(SUBSTR(buf,INSTR(buf,',',1,1)+1, INSTR(buf,',',1,2)-INSTR(buf,',',1,1)-1));
DBMS_OUTPUT.PUT_LINE(BUF || ' ' || v_service_id || ' ' || v_result3_value );
IF LENGTH(v_service_id) = 0 OR v_service_id IS NULL THEN
Dbms_output.put_line ('No Service_id' ||buf);
Raise Invalid_service_id;
END IF;
BEGIN
SELECT da.result1_value Bund_mins
, da.result2_value Bund_Rate
, da.result3_value Normal_Rate
, pi.product_id
FROM product_instance_history pi
, service_history sh
, derived_attribute_array da
, service_da_array sa
WHERE pi.product_instance_id = sh.base_product_instance_id
AND sh.service_id = sa.service_id
AND da.derived_attribute_id = 2005589
AND da.index3_value = 0 -- RATE BAND (FOR DURATION BASED TABLE )
AND da.index2_value = pi.product_id -- PRODUCT ID
AND da.index1_value = sa.result1_value -- RATEPLAN
AND sa.index1_value = 6 -- RCONNECT RATEPLAN TYPE
AND SYSDATE BETWEEN SA.EFFECTIVE_START_DATE AND SA.EFFECTIVE_END_DATE
AND sa.service_id = v_service_id
AND sa.derived_attribute_id = 1005715;
--UBU_RECORDS unbilled_usage%ROWTYPE
-- IF i.Normal_Rate <> '' and v_result3_value <> ''
IF v_result3_value <> ''
THEN
v_total_usage := TO_NUMBER (i.Normal_Rate) * TO_NUMBER (v_result3_value);
INSERT INTO table_temp
VALUES (v_service_id, v_total_usage );
END IF;
END;
END;
END LOOP;
EXCEPTION
WHEN UTL_FILE.invalid_path
THEN
raise_application_error
(-20000
, 'Invalid path. Set UTL_FILE_DIR'
);
WHEN Invalid_service_id
then
NULL;
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('Error :' || SQLERRM);
COMMIT;
UTL_FILE.fclose (fhandler);
END Update_RConnect_usage;
/
29/11 PLS-00428: an INTO clause is expected in this SELECT statement
51/12 PL/SQL: Statement ignored
51/43 PLS-00201: identifier 'I.NORMAL_RATE' must be declared
52/12 PL/SQL: SQL Statement ignored
|
|
|
|
|
Goto Forum:
Current Time: Sat Dec 02 16:50:23 CST 2023
|