Home » SQL & PL/SQL » SQL & PL/SQL » New to PL/SQL- How to read from file to write to database table -Tina
icon5.gif  New to PL/SQL- How to read from file to write to database table -Tina [message #148803] Mon, 28 November 2005 04:47 Go to next message
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 #148806 is a reply to message #148803] Mon, 28 November 2005 04:56 Go to previous messageGo to next message
Maaher
Messages: 7065
Registered: December 2001
Senior Member
The cause of your errors is:
1) your user probably has no execute right on UTL_FILE
2) You should use SINGLE QUOTES instead of double quotes.

Also note that the directory should be on the server, not the client.

MHE
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 Go to previous messageGo to next message
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 Go to previous messageGo to next message
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 Wink)
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 #148901 is a reply to message #148803] Mon, 28 November 2005 23:39 Go to previous messageGo to next message
tina_m
Messages: 7
Registered: November 2005
Junior Member
Thanks really. I got the answers to all my queries, thnx to you, even though you could not understand one question. There couldnot heve been a better way to clear my doubts.

-Tina
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 Go to previous messageGo to next message
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
Re: New to PL/SQL- How to read from file to write to database table -Tina [message #148947 is a reply to message #148944] Tue, 29 November 2005 03:19 Go to previous messageGo to next message
Maaher
Messages: 7065
Registered: December 2001
Senior Member
Tina, try to format your code and put it in code tags. It is extremely hard to read like this.

Now, in PL/SQL you need to add an INTO clause:
SELECT something
  INTO a_plsql_variable
  FROM yourtable
 WHERE ...

For each column in your select, you need a corresponding PL/SQL variable to hold the value. Read the documentation for more information.

Note that the above statement will fail if
  • there are no records that match
  • there are more than 1 records that match
MHE
Re: New to PL/SQL- How to read from file to write to database table -Tina [message #149075 is a reply to message #148803] Tue, 29 November 2005 23:31 Go to previous message
tina_m
Messages: 7
Registered: November 2005
Junior Member
yeah, it worked...........thnx
Previous Topic: SQL challenge
Next Topic: How to rename the column
Goto Forum:
  


Current Time: Sat Dec 02 16:50:23 CST 2023