Print text in Oracle SQL Developer SQL Worksheet window - oracle

I am using Oracle SQL (in SQLDeveloper, using the SQL Worksheet). I would like to print a statement before my select, such as
PRINT 'Querying Table1';
SELECT * from Table1;
What do I use to Print / show text output? It's not Print, because that gives me the error: Bind Variable Table1 is NOT DECLARED. DBMS_OUTPUT.PUT_LINE is an unknown command. (Obviously, I'm an inexperienced SQLDeveloper and Oracle user. There must be some synonym for Print, but I'm having trouble finding help on it without knowing what it is.)

for simple comments:
set serveroutput on format wrapped;
begin
DBMS_OUTPUT.put_line('simple comment');
end;
/
-- do something
begin
DBMS_OUTPUT.put_line('second simple comment');
end;
/
you should get:
anonymous block completed
simple comment
anonymous block completed
second simple comment
if you want to print out the results of variables, here's another example:
set serveroutput on format wrapped;
declare
a_comment VARCHAR2(200) :='first comment';
begin
DBMS_OUTPUT.put_line(a_comment);
end;
/
-- do something
declare
a_comment VARCHAR2(200) :='comment';
begin
DBMS_OUTPUT.put_line(a_comment || 2);
end;
your output should be:
anonymous block completed
first comment
anonymous block completed
comment2

PROMPT text to print
Note: must use
Run as Script (F5)
not
Run Statement (Ctl + Enter)

The main answer left out a step for new installs where one has to open up the dbms output window.
Then the script I used:
dbms_output.put_line('Start');
Another script:
set serveroutput on format wrapped;
begin
DBMS_OUTPUT.put_line('jabberwocky');
end;

You could set echo to on:
set echo on
REM Querying table
select * from dual;
In SQLDeveloper, hit F5 to run as a script.

You could put your text in a select statement such as...
SELECT 'Querying Table1' FROM dual;

For me, I could only get it to work with
set serveroutput on format word_wrapped;
The wraped and WRAPPED just threw errors: SQLPLUS command failed - not enough arguments

If I ommit begin - end it is error. So for me this is working (nothing else needed):
set serveroutput on;
begin
DBMS_OUTPUT.PUT_LINE('testing');
end;

If you don't want all of your SQL statements to be echoed, but you only want to see the easily identifiable results of your script, do it this way:
set echo on
REM MyFirstTable
set echo off
delete from MyFirstTable;
set echo on
REM MySecondTable
set echo off
delete from MySecondTable;
The output from the above example will look something like this:
-REM MyFirstTable
13 rows deleted.
-REM MySecondTable
27 rows deleted.

Related

PL/SQL DB Deployment Script

I'm trying to write a deployment script to run with SQL*Plus in a CI/CD pipeline but I can't find my way around what seems to be a very basic issue.
Here's a shortened version of the script release.sql:
DECLARE
vnum NUMBER;
BEGIN
SELECT COUNT(tname) INTO vnum FROM tab WHERE tname = 'DA_VERSION';
IF vnum = 0 THEN -- run create scripts
#ddl/da_001.sql
#ddl/da_002.sql
#dml/version.sql -- set initial version
END IF;
END;
da_001.sql looks like this:
CREATE TABLE TABLE_NAME
(
COLUMN1 NUMBER NOT NULL
, CONSTRAINT TABLE_NAME_PK PRIMARY KEY
(
COLUMN1
)
ENABLE
);
When I run
sqlplus.exe connection_string #release.sql
I get
CREATE TABLE DA_PRODUCTS
*
ERROR at line 6:
ORA-06550: line 6, column 1:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:...
So it doesn't like the CREATE statement at the beginning of da_001.sql but I don't know why. What am I missing here?
Create an installation file for your scripts, ie
install.sql
===========
#ddl/da_001.sql
#ddl/da_002.sql
#dml/version.sql -- set initial version
and then selectively call it via a wrapper in SQL Plus
set feedback off
set pages 0
spool /tmp/runme.sql
select
case when COUNT(tname) = 0 then '##install.sql' else 'pro Skipped install.sql' end
FROM tab WHERE tname = 'DA_VERSION';
spool off
#/tmp/runme.sql
As others have said there is a strict separation between what SQL*PLus understands/is capable of and what is within the SQL and PLSQL languages.
Script handling is one of these distinct areas, which means you cannot executing a SQL script within a PLSQL block.
Also, SQL*Plus does not have any understanding of PLSQL logic constructs.
However, looking at your requirement there might be a way. The answer from #"Connor McDonald" should work. Here is my attempt using a more PLSQL based approach.
This approach uses SQLPLus variables, which can be referenced and amended in both PLSQL and SQLPlus.
First you need a 'No Op' script since when using the SQL*PLus '#' you must specify a valid script name:
noop.sql:
PROMPT No Op
Now your controller script:
-- Declare your variables
VAR script1 VARCHAR2(256)
VAR script2 VARCHAR2(256)
VAR script3 VARCHAR2(256)
DECLARE
vnum NUMBER;
BEGIN
:script1 := 'noop.sql';
:script2 := 'noop.sql';
:script3 := 'noop.sql';
SELECT COUNT(tname) INTO vnum FROM tab WHERE tname = 'DA_VERSION';
IF vnum = 0 THEN -- run create scripts
-- Set variables
:script1 := 'ddl/da_001.sql';
:script2 := 'ddl/da_002.sql';
:script3 := 'dml/version.sql'; -- set initial version
END IF;
END;
/
-- Make variables referencable as SQLPLus defines
COLUMN s1 NEW_VALUE s1
COLUMN s2 NEW_VALUE s2
COLUMN s3 NEW_VALUE s3
SELECT :script1 s1, :script2 s2, :script3 s3
FROM dual;
-- RUN !!
# &&s1
# &&s2
# &&s3
The 3 scriptn variables can be used in PLSQL.
To use as SQL_PLus substition variable (&) we use the COL ... NEW_VALUE command to map a SELECT list column alias to a substituion variable. So we will effectively map scriptn to subs variabl;e sn.
After the PLSQL blocks completes the scriptn variables will have teh value 'noop.sql' or the name of teh script to run.
Then at the end, reference the subs variables in the '#' commands.
Anything with 'noop.sql' will execute a blank script.
I haven't used this myself but you might try something like this (simplified demo):
declare
vnum number := 0;
begin
--select count(tname) into vnum from tab where tname = 'DA_VERSION';
if vnum = 0 then -- include create script
execute immediate q'[
#callthis.sql
]';
end if;
end;
To work within execute immediate, the called script must contain a single statement and no semicolon.

My long time SQL*Plus loop doesn't print DBMS_OUTPUT.PUT_LINE output during execution

I know that in order to print something on sqlplus like below:
begin
dbms_output.put_line('Hello!');
end;
/
I need to call
set serveroutput on;
before that.
I also know that is not needed, but I can also call
DBMS_OUTPUT.enable;
before, just in case. This is working for me.
But what if I want to keep printing the progress of a long loop? It seems impossible to me. I've tried everything to print some progress on the loop below but just doesn't work. Is there some way of doing that? I even tried to spool to a file and didn't work.
Note 1: I can't truncate or partition this table as the DBA doesn't want to help me with that, so I have to use this nasty loop...
Note 2: I've noticed that once the loop is done, the whole output is printed. Looks like oracle is buffering the output and printing everything at the end. I'm not sure how to avoid that and print on every loop iteration.
set serveroutput on;
declare
e number;
i number;
nCount number;
f number;
begin
DBMS_OUTPUT.enable;
dbms_output.put_line('Hello!');
select count(*) into e from my_big_table where upd_dt < to_date(sysdate-64);
f :=trunc(e/10000)+1;
for i in 1..f
loop
delete from my_big_table where upd_dt < to_date(sysdate-64) and rownum<=10000;
commit;
DBMS_OUTPUT.PUT_LINE('Progress: ' || to_char(i) || ' out of ' || to_char(f));
end loop;
end;
Thank you for any answer.
There are 2 standard ways for such things:
set module and action in your session DBMS_APPLICATION_INFO.SET_MODULE:
SQL> exec DBMS_APPLICATION_INFO.SET_MODULE('my_long_process', '1 from 100');
PL/SQL procedure successfully completed.
SQL> select action from v$session where module='my_long_process';
ACTION
----------------------------------------------------------------
1 from 100
set session_longops:
DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS
I'd recommend it in your case since that is exactly designed for long operations.
Example on Oracle-Base.
----
PS: dbms_output,put_line saves all output in a collection (nested table) variable of dbms_output package, so you can't get it from another session and client can't get it during user call (execution). In addition to set serveroutput on you can also get the output using dbms_output.get_lines: http://orasql.org/2017/12/10/sqlplus-tips-8-dbms_output-without-serveroutput-on/
Btw, in case if you need to filter or analyze output from dbms_output, sometimes it's convenient to get output in a query, so you can use filter strings in where clause or aggregate them: https://gist.github.com/xtender/aa12b537d3884f4ba82eb37db1c93c25
DBMS_OUTPUT will only ever be displayed after the PL/SQL code has terminated and control has returned to the calling program.
Output is, as you found, buffered. When your PL/SQL code finishes, then the calling program (e.g. SQL*Plus) can go and fetch that output.
Insert into another table, maybe call it "MYOUTPUT".
Create the table:
create table myoutput (lineno number, outline varchar2(80));
Add this after your delete:
insert into MYOUTPUT values (i,'Progress: ' || to_char(i) || ' out of ' || to_char(f));
Then select from MYOUTPUT periodically to see progress.
select outline from myoutput order by lineno;
Bobby
You can use UTL_FILE to write output to an external file, as in:
DECLARE
fh UTL_FILE.FILE_TYPE;
nRow_count NUMBER := 0;
BEGIN
fh := UTL_FILE.FOPEN('DIRECTORY_NAME', 'some_file.txt', 'w');
FOR aRow IN (SELECT *
FROM SOME_TABLE)
LOOP
nRow_count := nRow_count + 1;
IF nRow_count MOD 1000 = 0 THEN
UTL_FILE.PUT_LINE(fh, 'Processing row ' || nRow_count);
UTL_FILE.FFLUSH(fh);
END IF;
-- Do something useful with the data in aRow
END LOOP; -- aRow
UTL_FILE.FCLOSE_ALL; -- Close all open file handles, including
-- the ones I've forgotten about...
END;

How can I skip printing an SQL script but still show the DBMS values?

I'm developing a code and would like to see in the results only the actual values, instead of the script I executed.
So I'm trying to develop a "table rows counter" and I've been quite successful, but I still get the full executed script, when I only need its results.
Let's say, my code is:
DECLARE
VAR_1 NUMBER := 0;
BEGIN
SELECT IMITM INTO VAR_1 FROM PRODDTA.F4101 WHERE ROWNUM <= 1;
DBMS_OUTPUT.PUT_LINE('DUMMY TEST 1' || VAR_1);
DBMS_OUTPUT.PUT_LINE('DUMMY TEST 2');
END;
/
Well, by clicking F5 I would see:
DUMMY TEST 150041087
DUMMY TEST 2
PL/SQL procedure successfully completed.
In the complete code it reads about 200 lines of only code, so...
How can I get only the output lines, and in this case, remove the "PL/SQL procedure..." legend?
I've tried unsuccessfully yo use "SET FEED" and "SET TERM" off.
According to Oracle documentation:
SET FEEDBACK OFF also turns off the statement confirmation messages
such as 'Table created' and 'PL/SQL procedure successfully completed'
that is displayed after successful SQL or PL/SQL statements.
You need to use SET FEEDBACK OFF as following:
SQL> SET SERVEROUT ON
SQL> SET FEEDBACK OFF
SQL> DECLARE
2 VAR_1 NUMBER := 0;
3 BEGIN
4 SELECT
5 1
6 INTO VAR_1
7 FROM
8 DUAL
9 WHERE
10 ROWNUM <= 1;
11
12 DBMS_OUTPUT.PUT_LINE('DUMMY TEST 1' || VAR_1);
13 DBMS_OUTPUT.PUT_LINE('DUMMY TEST 2');
14 END;
15 /
DUMMY TEST 11
DUMMY TEST 2
SQL>
SQL>
Cheers!!
I actually managed to do it by exploring SET commands.
For the SQL script "acknolwedgement", we can skip it with the following commands:
To disable the SQL & variables verification before the actual execution, use:
SET VERIFY OFF
To disable the post execution notes, as Tejash indicated already, use:
SET FEEDBACK OFF
So my prologue ends up being:
SET SERVERTOUTPUT ON;
SET VERIFY OFF;
SET FEEDBACK OFF;
Thanks a lot for the answers & comments.

PLSQL Passing Variables to External .SQL Scripts

I have 2 scripts, Script1.sql & Script2.sql. Script1.sql retrieves some data from a table in the database which I want to then pass to Script2.sql to use.
Script1.sql is as below:
SET SERVEROUTPUT ON;
DECLARE
FundRecord Test_Table%ROWTYPE;
CURSOR Fund_Cursor IS SELECT Code, YOURNAME FROM Test_Table;
BEGIN
OPEN Fund_Cursor;
LOOP
FETCH Fund_Cursor INTO FundRecord;
EXIT WHEN Fund_Cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Script1: ' || FundRecord.Code);
END LOOP;
CLOSE Fund_Cursor;
END;
/
#C:\Temp\Script2.sql FundRecord.Code;
And Script2.sql is as below:
BEGIN
DBMS_OUTPUT.PUT_LINE('Script 2:' || ' ' || '&1');
END;
/
The output from Script1.sql and Script2.sql is as follows:
Script1: ABDCE
Script2: FundRecord.Code
Why is the output of Script2 FundRecord.Code and not 'ABCDE' as I would expect?
How do I pass this in to ensure that Script2 is getting 'ABCDE' as the parameter?
Thanks
The record FundRrecord only exists within the PL/SQL block. You need to declare a separate variable that you can use outside the block:
set autoprint on serverout on
var somevalue varchar2(20)
col somevalue new_value somevalue
begin
for r in (
select dummy from dual
)
loop
dbms_output.put_line('Script 1: ' || r.dummy);
:somevalue := r.dummy;
end loop;
end;
/
#C:\Temp\Script2.sql &somevalue
The column ... new_value ... syntax is provided in SQL*Plus for page headers and footers in reports, but it is also very useful in scripts as it sets a define variable from the (last) result of a query. set autoprint on tells SQL*Plus to print the values of any bind variables (the ones with a leading :) after each PL/SQL block, and helpfully it does this by generating a query, allowing us to set up a column ... new_value and capture the result in a substitution variable.
Edit: regarding SQL Developer compatibility, I'll try some things out when I get a chance, but you might try adding something along the lines of
select :somevalue as somevalue from dual;
after the PL/SQL block, in case the column ... new_value construction works the same as in SQL*Plus but autoprint does not.
You can try as
#Script2.sql param1
and in Script2 SQL file, refer the parameter as
&1
Update 1
Here is my test case which works fine.
SELECT SYSDATE FROM &1;
This SQL statement is saved as Test.sql and it is invoked from SQLPLUS as
#D:\Test.sql dual
where dual is the parameter which been passed to Test.sql file
Result is displayed in the below screenshot

anonymous block completed in oracle SQL

Whilst trying to create a query cursor as follows:
DECLARE CURSOR Query1
IS
SELECT * FROM RACE
WHERE Race_Time='22-SEP-14 12.00.00.000000000';
BEGIN
OPEN Query1;
END;
I get the following error. anonymous block completed. Does anyone know how to fix this? I tried setting the
'SET SERVEROUTPUT ON;'
before the declare but this did not seem to fix the error. Thanks in advance!
It seems that dbms_output is turned off
you can see you out put if you put SET SERVEROUTPUT ON; in the beginning of your script.
or you can view dbms_output window (View then DBMS Output) then press the "+" at the top of the Dbms Output window and then select an open database
"anonymous block completed" means your PL/SQL code was successfully executed.
To Display: try using a output statement...
For example:
BEGIN
dbms_output.put_line ('Hello, world!');
END;
If you want to control the process in PL/SQL, you could do something like
DECLARE
l_race_rec race%rowtype;
CURSOR Query1
IS
SELECT *
FROM RACE
WHERE Race_Time='22-SEP-14 12.00.00.000000000';
BEGIN
OPEN Query1;
LOOP
FETCH query1 INTO l_race_rec;
EXIT WHEN query1%notfound;
dbms_output.put_line( l_race_rec.column1 || ' ' || l_race_rec.column2 || ... || l_race_rec.columnN );
END LOOP;
CLOSE Query1;
END;
Unless your assignment requires the use of explicit cursors, though, implicit cursors are likely easier to use
BEGIN
FOR x IN( SELECT *
FROM RACE
WHERE Race_Time='22-SEP-14 12.00.00.000000000')
LOOP
dbms_output.put_line( x.column1 || ' ' || x.column2 || ... || x.columnN );
END LOOP;
END;
If you are using SQL*Plus, you can also do something like
VAR rc REFCURSOR;
BEGIN
OPEN :rc
FOR SELECT *
FROM race
WHERE race_time = '22-SEP-14 12.00.00.000000000';
END;
PRINT rc
If race_time is really a timestamp, you should really be comparing a timestamp with another timestamp rather than comparing a timestamp to a string. Use explicit conversion with an explicit format mask to avoid errors due to different sessions having different NLS settings
WHERE race_time = to_timestamp( '22-SEP-14 12.00.00.000000000',
'DD-MON-RR HH24:MI:SS.FF9' )
Of course, I'm not sure why you would use a timestamp in the first place here-- it seems unlikely that you really know the nanosecond at which a race started.

Resources