Number of rows inserted/updated in utl_file - sql

How do i print number of rows in utl_file.
If i am using dbms_output.put_line('Total record'||'|'||SQL%ROWCOUNT);
and
If i am ​using dbms_output.put_line('Total record'||'|'||To_char(SQL%ROWCOUNT));
Compiler saying wrong argument is passed. nothing is reflecting
and
utl_file.put(file_handele,'total roecord' ||'|'|| SQL%ROWCOUNT);
only total record is reflecting.
please help new to psql

What do you call "number of rows in utl_file"?
You said that 1st and 2nd statements are invalid because compiler is complaining. It is not for me, so I kind of doubt what you claim:
SQL> begin
2 -- your 1st statement:
3 dbms_output.put_line('Total record'||'|'||SQL%ROWCOUNT);
4
5 -- your 2nd statement:
6 dbms_output.put_line('Total record'||'|'||To_char(SQL%ROWCOUNT));
7 end;
8 /
Total record|
Total record|
PL/SQL procedure successfully completed.
As of the 3rd statement:
SQL> declare
2 file_handele utl_file.file_type;
3 begin
4 file_handele := utl_file.fopen('EXT_DIR', 'test.txt', 'w');
5
6 -- your 3rd statement, literally, with typos:
7 utl_file.put(file_handele,'total roecord' ||'|'|| SQL%ROWCOUNT);
8
9 utl_file.fclose(file_handele);
10 end;
11 /
PL/SQL procedure successfully completed.
SQL> $type c:\temp\test.txt
total roecord|
SQL>
All 3 statements are OK (i.e. they don't fail, they don't raise an error), but the question is: which problem are you trying to solve? Display number of rows written into a file using UTL_FILE package? If so, you should have posted that piece of code as well.
Anyway: one option is to literally count them. For example:
SQL> declare
2 i number := 0; -- this is the counter
3 file_handele utl_file.file_type;
4 begin
5 file_handele := utl_file.fopen('EXT_DIR', 'test.txt', 'w');
6
7 for cur_r in (select dname from dept) loop
8 utl_file.put(file_handele, cur_r.dname || utl_tcp.crlf);
9 i := i + 1; -- increment the counter
10 end loop;
11
12 -- your 3rd statement, literally, with typos:
13 utl_file.put(file_handele,'total roecord' ||'|'|| i);
14
15 utl_file.fclose(file_handele);
16 end;
17 /
PL/SQL procedure successfully completed.
The result:
SQL> $type c:\temp\test.txt
ACCOUNTING
RESEARCH
SALES
OPERATIONS
total roecord|4 --> here's the total number of lines written into the file
SQL>

Related

PL/SQL CREATE PROCEDURE - factorial

I don't know what's wrong with my code block to create a procedure to find out the factorial of a number. Thank you.
Question 1: write a stored procedure that gets an integer number n and calculates and displays its factorial.
SET SERVEROUTPUT ON;
CREATE OR REPLACE PROCEDURE factorial_number(
n NUMBER) AS
factorial NUMBER;
num Number;
BEGIN
FOR i IN REVERSE 1..n LOOP
num := i - 1;
factorial := factorial * num;
END LOOP;
DBMS_OUTPUT.PUT_LINE (factorial);
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.PUT_LINE ('Error!');
END;
/
BEGIN
factorial_number(5);
END;
/
You're failing to initialize the local variable factorial. Uninitialized variables are initially null and multiplying null by any value produces null.
I don't see why you'd want your loop to go in reverse order. It doesn't matter since multiplication is communitive but it it unlikely to make your code easier to read/ debug/ follow.
You don't want to subtract 1 from the value you are multiplying by on each iteration of the loop. When i = 1, for example, you're multiplying factorial by 0 which means that (assuming you initialize factorial), you'd always end up with 0. You want to multiply by i so there is no need for the local variable num.
If I make those fixes
CREATE OR REPLACE PROCEDURE factorial_number(
n NUMBER)
AS
factorial NUMBER := 1; -- Initialize
BEGIN
FOR i IN 1..n LOOP -- Loop normally
dbms_output.put_line( 'Beginning iteration ' || i || ' of loop. ' ||
'Factorial = ' || factorial ||
' multiplying by ' || i );
factorial := factorial * i; -- Multiply by i not i-1
END LOOP;
DBMS_OUTPUT.PUT_LINE (factorial);
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.PUT_LINE ('Error!');
END;
Then
BEGIN
factorial_number(5);
END;
will print out 120 (5*4*3*2*1).
I'm also adding an additional dbms_output line to print out the current state of the variables on each iteration of the loop. That's a relatively old-school method of debugging. In the modern world, you'd walk through the code with a debugger where you can see the values of your local variables but introductory classes may not teach debugger usage initially.
How about
SQL> CREATE OR REPLACE PROCEDURE factorial_number (n NUMBER)
2 AS
3 factorial NUMBER := 1;
4 BEGIN
5 FOR i IN 1 .. n
6 LOOP
7 factorial := factorial * i;
8 END LOOP;
9
10 DBMS_OUTPUT.PUT_LINE (factorial);
11 END;
12 /
Procedure created.
SQL>
SQL> BEGIN
2 factorial_number (5);
3 END;
4 /
120
PL/SQL procedure successfully completed.
SQL>

How to write PL/SQL block to get the addition of the number? Exa. if entering 245 it should process the addition like 2+4+5

I need to write a block in PL/SQL which may results into the addition of the number inputted.
For example, if I'm entering 245 so it should gives the output like addition if these 3 number(I.e. 2+4+5).
I hope you got my query.
Thanks in advance.
You don't really need PL/SQL for that.
SQL> set ver off
SQL>
SQL> select sum(dig) result
2 from (select substr(&&enter_number, level, 1) dig
3 from dual
4 connect by level <= length(&&enter_number)
5 );
Enter value for enter_number: 245
RESULT
----------
11
It is a simple task to rewrite it to a function:
SQL> create or replace function f_dig (par_enter_number in number)
2 return number
3 is
4 retval number;
5 begin
6 select sum(dig)
7 into retval
8 from (select substr(par_enter_number, level, 1) dig
9 from dual
10 connect by level <= length(par_enter_number)
11 );
12 return retval;
13 end;
14 /
Function created.
SQL> select f_dig(245) result_1,
2 f_dig(189) result_2,
3 f_dig(9834188) result_3
4 from dual;
RESULT_1 RESULT_2 RESULT_3
---------- ---------- ----------
11 18 41
SQL>
You may try below function for the same -
CREATE OR REPLACE FUNCTION digit_sum(P_N NUMBER)
RETURN NUMBER
IS
n number := P_N;
s number := 0;
m number := 0;
BEGIN
WHILE (n > 0) LOOP
m := MOD(n, 10);
s := s + m;
n := TRUNC(n/10);
END LOOP;
RETURN (s);
END digit_sum;
/
Here is the fiddle.

Reference cursor gets lost in XMLType.createxml

I am calling a function that returns a reference cursor, and I am using XMLType.createxml to convert the results to XML, e.g.
select XMLType.createxml(package_name.storedProcName('PARAM1', 'PARAM2', 'PARAM3')) as sresult from dual;
However, I have found this to have an unwelcome side-effect. It seems that the cursor used to retrieve the data for the XMLType is never closed. After calling the function many times using this technique, I always run into the following error:
ORA-01000: maximum open cursors exceeded
I do not have a handle to the cursor, thus I cannot manually close it. Also, we are using pooled connections, so there is no connection reset where these cursors can be automatically released. What can be done about this?
Here is my Oracle version (as returned from v$version):
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
PL/SQL Release 10.2.0.5.0 - Production
CORE 10.2.0.5.0 Production
TNS for HPUX: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - Production
(For those interested, here is a link to my previous question related to XMLType.)
There seems to be a bug, you should open a service request to Oracle support. I'll post a test case that reproduces your finding in 9i and 11.2.0.3:
SQL> SHOW parameter open_cursors
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
open_cursors integer 600
SQL> CREATE OR REPLACE FUNCTION ret_cursor RETURN SYS_REFCURSOR IS
2 l SYS_REFCURSOR;
3 BEGIN
4 OPEN l FOR
5 SELECT * FROM dual;
6 RETURN l;
7 END;
8 /
Function created
XMLType will not close cursors correctly when called with the above function, whereas it works well with static SQL:
SQL> /* Works as expected with static cursor */
2 DECLARE
3 l XMLTYPE;
4 BEGIN
5 FOR i IN 1 .. 1e4 LOOP
6 SELECT xmltype.createXML(CURSOR(SELECT * FROM DUAL)) INTO l FROM dual;
7 END LOOP;
8 END;
9 /
PL/SQL procedure successfully completed
SQL> /* Fails with call to dynamic cursor */
SQL> DECLARE
2 l XMLTYPE;
3 BEGIN
4 FOR i IN 1 .. 1e4 LOOP
5 SELECT xmltype.createXML(ret_cursor) INTO l FROM dual;
6 END LOOP;
7 END;
8 /
DECLARE
*
ERROR at line 1:
ORA-01000: maximum open cursors exceeded
ORA-06512: at "APPS.RET_CURSOR", line 4
ORA-06512: at line 5
You should be able to use a wrapper function to prevent the ORA-01000 from happening (tested on 9iR2, 11gR2):
SQL> CREATE OR REPLACE FUNCTION wrap_xml(p SYS_REFCURSOR) RETURN XMLTYPE IS
2 l XMLTYPE;
3 BEGIN
4 l := xmltype.CreateXML(p);
5 IF p%ISOPEN THEN
6 CLOSE p;
7 END IF;
8 RETURN l;
9 END;
10 /
Function created
SQL> DECLARE
2 l XMLTYPE;
3 BEGIN
4 FOR i IN 1 .. 1e4 LOOP
5 l := wrap_xml(ret_cursor); -- a SELECT FROM dual will still fail here
6 -- on 9i but not on 11g
7 END LOOP;
8 END;
9 /
PL/SQL procedure successfully completed

How to properly output PL/SQL

I have two blocks of code inside a .sql file. One block is a function and another is a procedure. In the first block, I'm running a query and printing it out to the screen (I'm using DBMS_OUTPUT.PUT_LINE() ) for each row in it's own line. Then the procedure has another query which needs to be printed on the same line (I'm using DBMS_OUTPUT.PUT() ). When I use DBMS_OUTPUT.PUT() for the second block, it screws up the first block for some reason and the first block never prints.
Here's a link to the code: http://pastebin.com/z29emmBJ
(The relevant part of the code is around lines: 97-103)
When I have DBMS_OUTPUT.PUT_LINE() being used inside of the procedure, everything displays properly, but when I have DBMS_OUTPUT.PUT() inside of the procedure, it looks like the function never gets called.
Here's what the output looks like with PUT_LINE(): http://i.imgur.com/AnCv9.png
Here's what the output looks like with just PUT(): http://i.imgur.com/Jv3SV.png
I think it has something to do with the buffer size, but I'm not exactly sure what/why.
Any help would be greatly appreciated!
Why don't you just append the results to a VARCHAR2 variable as needed, then put_line that string when the row is completed? That way you have control over the formatting.
Snippet of the code of your Second stored procedure:
FOR player IN rows LOOP
currentCount := maxCount;
DBMS_OUTPUT.PUT(player.FIRSTNAME || ' ' || player.LASTNAME || ':' || player.points || ' ');
--DBMS_OUTPUT.NEW_LINE();
END LOOP;
If you want that the resulting output appeared as a one line you should move DBMS_OUTPUT.NEW_LINE() outside the loop (after the loop). So your code would look like:
FOR player IN rows LOOP
currentCount := maxCount;
DBMS_OUTPUT.PUT(player.FIRSTNAME || ' ' || player.LASTNAME || ':' || player.points || ' ');
END LOOP;
DBMS_OUTPUT.NEW_LINE();
Keeping DBMS_OUTPUT.NEW_LINE(); inside the loop after DBMS_OUTPUT.PUT you just emulating DBMS_OUTPUT.PUT_LINE procedure.
SQL> create or replace procedure output1
2 is
3 l_str varchar2(100);
4 l_status number;
5 begin
6 for i in 1..7
7 loop
8 dbms_output.put('Text_' || To_char(i));
9 dbms_output.new_line;
10 end loop;
11 end;
12 /
Procedure created
SQL>
SQL> create or replace procedure output2
2 is
3 l_str varchar2(100);
4 l_status number;
5 begin
6 for i in 1..7
7 loop
8 dbms_output.put('Text_' || To_char(i));
9 end loop;
10 dbms_output.new_line;
11 end;
12 /
Procedure created
SQL> exec output1;
Text_1
Text_2
Text_3
Text_4
Text_5
Text_6
Text_7
PL/SQL procedure successfully completed
SQL> exec output2;
Text_1Text_2Text_3Text_4Text_5Text_6Text_7
PL/SQL procedure successfully completed
In your code:
SET serveroutput ON size 32000;
REM Change output file name TO proj3-NetID.OUT!
SPOOL proj3-hgeorge3.OUT;
exec DBMS_OUTPUT.enable('100000000');
If serveroutput option is used (set to ON) then there is no need of calling DBMS_OUTPUT.enable procedure. And if it happens to call DBMS_OUTPUT.enable then the value of numeric data type should be passed in as a parameter not a string. Yes there will be implicit conversion of data types but it's better to avoid it. And maximum size of the buffer is 1 million.

oracle pl/sql ora-01722 error

I have a simple oracle statement in my procedure:
update org.security_training_question a
set a.actv_indr = 'N' where a.qstn_id in (v_qstns_to_delete);
v_qstns_to_delete is a parameter being passed. It is a varchar2 field and a.qstn_id is a numeric field.
When calling the Stored Procedure, for v_qstns_to_delete I am passing the following String: "24, 43, 23, 44, 21".
When I run the statement output the stored procedure thenn it runs fine but when I run it as a stored procedure I get an error on the above line saying Invalid Number.
Any clue?
You can't use a "in" clause with a variable like that. One way around it is
declare stmt varchar2(4000);
begin
stmt := 'update org.security_training_question a set a.actv_indr = ''N'' where a.qstn_id in ('||v_qstns_to_delete||')';
execute immediate stmt;
end;
if v_qstns_to_delete is a varchar, you would need to convert it somewhat to let Oracle understand that there may be several items in it. One method would be to convert the string to a table of items.
Supposing qstn_id is a NUMBER column, you would:
SQL> CREATE TYPE tab_number AS TABLE OF NUMBER;
2 /
Type created
SQL> CREATE OR REPLACE FUNCTION to_tab_number(p_in VARCHAR2,
2 p_separator VARCHAR2 DEFAULT ',')
3 RETURN tab_number AS
4 l_result tab_number := tab_number();
5 l_tail LONG := p_in;
6 BEGIN
7 WHILE l_tail IS NOT NULL LOOP
8 l_result.EXTEND;
9 IF instr(l_tail, p_separator) != 0 THEN
10 l_result(l_result.COUNT) := to_number(substr(l_tail,
11 1,
12 instr(l_tail, p_separator) - 1));
13 l_tail := substr(l_tail, instr(l_tail, p_separator) + 1);
14 ELSE
15 l_result(l_result.COUNT) := to_number(l_tail);
16 l_tail := NULL;
17 END IF;
18 END LOOP;
19 RETURN l_result;
20 END;
21 /
Function created
You could then convert a string to a table of number from SQL:
SQL> SELECT * FROM TABLE(to_tab_number('24, 43, 23, 44, 21'));
COLUMN_VALUE
------------
24
43
23
44
21
To do a variable in-list:
SQL> SELECT object_id, owner
2 FROM all_objects
3 WHERE object_id IN (SELECT column_value FROM TABLE(to_tab_number('18,19,20')));
OBJECT_ID OWNER
---------- ------------------------------
18 SYS
19 SYS
20 SYS
More on the same subject on askTom.