Oracle PL/SQL's dbms_output.put_line() vs dbms_output.put() - oracle

I have a trivial question, I yet to understand the difference between dbms_output.put_line() and dbms_output.put()
set serveroutput on size 200000
Begin
dbms_output.put_line('A' || CHR(10) || 'B');
End;
/
exec dbms_output.put_line('A' || CHR(10) || 'B');
The above gives output A and B in two different lines. But
exec dbms_output.put('A')
exec dbms_output.put('B')
exec dbms_output.new_line
prints nothing. I am using SQL*Plus: Release 11.2.0.1.0 Production

You always have to write full lines in each PL/SQL block. Wehn you write
Begin
dbms_output.put_line('A' || CHR(10) || 'B');
End;
/
You write the two full lines "A" and "B" in one PL/SQL block. When you write
exec dbms_output.put_line('A' || CHR(10) || 'B');
the same holds true.
But when you write
exec dbms_output.put('A')
exec dbms_output.put('B')
exec dbms_output.new_line
you have three separate PL/SQL blocks. The first two write partial lines, which will be skipped by SqlPlus. The third block writes a full, but empty line.
If you write
begin
dbms_output.put('A');
dbms_output.put('B');
dbms_output.new_line;
end;
/
everything works as expected.
The reason for this is how console output in SqlPlus works: PL/SQL writes the output in an intermediate buffer. SqlPlus fetches the content of this buffer at the end of each executed PL/SQL block. It then prints that content to the console, while only printing full lines. Hence it skips the last line in the buffer, when it is not terminated by a new line character.
Technically I suspect SqlPlus to also print lines without a new line character, but starightaway overwrite them in the next step. Technically SqlPlus indeed fetches only full lines from the internal buffer, using the DBMS_OUTPUT.GET_LINES PL/SQL function.

Assuming you are on 11g, you should be considering PUT procedure since it is Obsolete and no longer supported by Oracle. In previous versions, with PUT, the line is not yet completed. Since it doesn't have end of line marker unlike PUT_LINE which automatically is followed by an end-of-line marker.
So, if you add an end-of-line marker, you will get the output.
You can have a look at this old question Is dbms_output.put() being buffered differently from dbms_output.put_line()?

Related

Unable to get correct result from simple query in cmd PL/SQL

I was trying to print "Hello World", but I continue to get number 7 returned. Also, after the 7 is returned, I cannot run another file without restarting cmd window. If I hit enter key, the number increments by 1. Please explain why this is happening and possible ways to correct.
Put a / on a new line at the end of the file to terminate the PL/SQL anonymous block.
SET SERVEROUTPUT ON;
DECLARE
name VARCHAR2(20);
BEGIN
name := 'Hello World';
DBMS_OUTPUT.PUT_LINE(name);
END;
/
SQL/Plus has read your file but has not found the statement terminator for the PL/SQL block so it is continuing to ask for more input to complete the statement. It is expecting a / character on a new line (the 7th line of the statement, the first being DECLARE as the SET command is a different statement) and when you press the enter key then it moves on to line 8 of the statement and is still expecting the terminator character so asks for more input (and repeats for the 9th, 10th and 11th lines).
You could press / then enter in SQL/Plus but it would be better to fix the file so it contains complete statements.

SQL*Plus script executed twice

I'm trying to run a script using sqlplus. My script is a simple delete statement. I execute it by putting the following in my ksh terminal:
sqlplus username/'password' #../sql/delete_societes.sql
../sql/delete_societes.sql is
DELETE FROM f2020.SOCIETES;
/
For some reason, it runs twice, causing the output "0 lines deteleted" to be printed twice and causing errors when I try to do an insert instead of a delete.
Make your script do either;
DELETE FROM f2020.SOCIETES
/
or
DELETE FROM f2020.SOCIETES;
without the slash.
From the documentation:
/(slash)
Executes the most recently executed SQL command or PL/SQL block which is stored in the SQL buffer.
and in the example further down:
Enter a slash (/) to re-execute the command in the buffer
... which is exactly what you are seeing.
Elsewhere in those docs:
The semicolon (;) means that this is the end of the command. Press Return or click Execute. SQL*Plus processes the command and displays the results
Like many clients SQL*Plus treats the semicolon at the end of your SQL statement as a statement separator - it is not part of the statement itself (which causes some confusion for e.g. dynamic SQL and JDBC calls) - and when it sees it it executes the command. The executed statement stays in the command buffer; and if you list to see the current command buffer, it will not show that semicolon. When you issue a slash it executes the buffer again.
Things are slightly different for PL/SQL; there the PL/SQL block has to be terminated with a semicolon, which is part of the block, and appears in the buffer. You have to use a slash to execute a PL/SQL block.
An example where you can see the sqlplus buffer content for SQL and PLSQL.
me#XEPDB1> help run
RUN
---
Lists and executes the most recently executed SQL command or
PL/SQL block which is stored in the SQL buffer. The buffer has
no command history list and does not record SQL*Plus commands.
R[UN]
me#XEPDB1> help /
/ (slash)
---------
Executes the most recently executed SQL command or PL/SQL block
which is stored in the SQL buffer. Use slash (/) at the command
prompt or line number prompt in SQL*Plus command line. The buffer
has no command history and does not record SQL*Plus commands.
/
me#XEPDB1> clear buffer [1/651]
buffer cleared
me#XEPDB1> l
SP2-0223: No lines in SQL buffer.
me#XEPDB1> select * from dual
2 /
D
-
X
me#XEPDB1> l
1* select * from dual
me#XEPDB1> select * from dual;
D
-
X
me#XEPDB1> l
1* select * from dual
me#XEPDB1> /
D
-
X
me#XEPDB1> r
1* select * from dual
D
-
X
me#XEPDB1> begin null; end;
2 /
PL/SQL procedure successfully completed.
me#XEPDB1> l
1* begin null; end;
me#XEPDB1> /
PL/SQL procedure successfully completed.
me#XEPDB1> r
1* begin null; end;
PL/SQL procedure successfully completed.

how to write a batch file, which runs a PL/SQL block, to tell me many records are inserted/deleted/etc. in a log file?

I have created two batch files to run two separate .sql file in Windows Task Scheduler. The batch file for both looks like this:
sqlplus userid/password#database #C:\XXX.sql>>C:\output.log
echo commit; | userid/password#database
The first .sql file (SQL1) is a PL/SQL block like this:
SET SERVEROUT ON
DECLARE
....
BEGIN
IF ...
....
ELSE
#D:\DM_FIX.sql;
END IF
END
The DM_FIX.sql file is to insert a bunch of records into a table, and it starts with the INSERT command.
The second.sql file is not a block file. It's doing a bunch of DDL/DML comand. the file looks like below:
Truncate Table YYY
Reuse Storage;
Commit;
Insert into Table YYY
Select ... from
Commit;
Delete from Table YYY
where ...
Commit;
When I run the second .sql file, I get an output that indicates "The table has been truncated; #### records are inserted; #### records are deleted..."
But when I run the first, although the PL/SQL procedure is executed successfully, I don't get a line saying how many records are inserted, and I'm trying to figure out a way to do it.
Does any one know what could be the trick?
Thanks!
Revised Answer
As #Alex Poole helpfully pointed out, you can use the # nomenclature in a PL/SQL block from SQL*Plus, as that would load the second file's commands into the block that you're calling it from.
The reason that you're not getting any output is that, as far as SQL*Plus is concerned it's all one command: the SQLPlus block. In order to get output to your log for those commands, you'll need to create it yourself, using DBMS_OUTPUT. You would need to include a line like the one below after each command.
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' rows inserted');
However, you should note that doing this will cause your script to throw errors if it's ever called from outside of a PL/SQL block. My original solution would avoid this restriction, as it eliminates the need to use DBMS_OUTPUT.
Original Answer
I find it difficult to believe that the PL/SQL in the first file is executing successfully. This is because you're mixing SQL*Plus commands with PL/SQL code. They are separate systems - it's like trying to use shell commands natively in a programming language. You should be getting PLS-00103: Encountered the symbol "#" when expecting... from the first file.
SQL*Plus doesn't have conditionals, so, in order to keep the PL/SQL and SQLPlus commands seperate, you'd need to fake it somewhat. I'd suggest putting the file name into a substitution variable, then using that to run a file:
VARIABLE v_my_file_bind varchar2(100)
DECLARE
...
BEGIN
IF ...
...
:v_my_file_bind := 'D:\EMPTY_FILE.sql';
ELSE
:v_my_file_bind := 'D:\DM_FIX.sql';
END IF;
END;
/
COLUMN v_my_file_column new_value my_file_substitution noprint
SELECT :v_my_file_bind v_my_file_column from dual;
#&&my_file_substitution
To show count of modified rows in PL/SQL, use SQL%ROWCOUNT:
begin
insert into my_table ...
select ...
from ...;
dbms_output.put_line('Rows inserted: ' || SQL%ROWCOUNT);
commit;
end;
/
Remember, that SQL%ROWCOUNT variable will reset to 0 after commit.
Documentation: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/sql_cursor.htm

How to return result of an Oracle stored procedure to a shell script

I have a oracle procedure proc1 which adds two values and gives the result.I have to call this procedure from shell and show its result back to the shell.I am able to call that procedure from the shell,but it just shows that PL/SQL procedure successfully completed.But the result is not coming to the shell .
i am doing this to call the procedure from shell...
$ echo "execute proc1(10,10);"|sqlplus -s system/xxxxx#orcl
This is the procedure which is running fine .
create or replace procedure proc1
(N1 in number,N2 in number) is
begin
dbms_output.put_line(N1+N2);
end;
/
I need the output in the shell .Anyone plese help.
I am aware there is another answer showing how to use set serveroutput on and the procedure call on separate lines, however I am writing this answer as a one-liner to do the same thing.
Bascially you need to shove this into sqlplus:
set serveroutput on
execute proc1(10,10);
You might at first think this can be done on one line, separated with a semi-colon.
set serveroutput on; execute proc1(10,10);
However that doesn't work - you really need a newline character.
So the trick is to also use -e flag with echo, which can give you a newline with \n.
Using head -1 trims everyting but the line containing the procedure result.
Final one-line answer:
echo -e "set serveroutput on\n execute proc1(10,10);"|sqlplus -s system/xxxxx#orcl| head -1
P.S. I editted your question to remove the password :)

call a oracle procedure from inside a sql block

If I have a .sql file with this :
begin
exec dbms_stats.gather_table_stats('schema',table');
end;
/
Should I need to use :
call 'exec dbms_stats.gather_table_stats('schema',table')';
I cannot test it out because of system problems so i am posting my query here.
As far as I can tell, both are flawed - exec is used in SQL/Plus without a begin/end block, and call is definitely not PL/SQL; you'd also probably have to escape the single quotes inside your call statement.
You can just use
begin
dbms_stats.gather_table_stats('ALERTS_OWNER','ASYNC_PROCESSING_REQUEST_T');
end;

Resources