Execute immediate run from a PL/SQL package - oracle

I have the following lines of code in a PL/SQL package
l_sql := 'alter table LOG_FILES location ('||chr(39)|| filename || to_char(sysdate,'DDMMYY') ||chr(39)||'))';
execute immediate l_sql;
The pl/sql package compiles fine but i dont see the change. The alter command has no effect at all. Is there any reason for this?
Note: The table I am trying to alter is an Oracle External table.

The filename is a string and needs to be bracketed with single quotes in the final statement. In order to acheive that you need to escape the single quote. One way is to use two single quotes. So, your assignment needs to look something like this:
l_sql := 'alter table LOG_FILES location ('''|| filename || to_char(sysdate,'DDMMYY') ||''')';

You have an extra parentheses at the end of your statement

Related

Using Variable- Oracle

In the above code, I am giving schemaname as input and using that input it should connect to the database. But In this case the value i entered is not taken by the schemaname. This is how the out put and the error is:
declare schemaname varchar2(20);
exec :schemaname := XYZ;
BEGIN
end;
Error report -
ORA-06550: line 2, column 6:
PLS-00103: Encountered the symbol "" when expecting one of the following:
constant exception <an identifier>
<a double-quoted delimited-identifier> table long double ref
char time timestamp interval date binary national character
nchar
ORA-06550: line 4, column 1:
PLS-00103: Encountered the symbol "CONNECT" when expecting one of the following:
Could any one suggest how to make it work using spool
the code between declare and end is PL/SQL. Commands like CONNECT or SPOOL are SQL*Plus commands. You cannot use SQL*Plus commands in a PL/SQL block.
In your case you don't need PL/SQL at all:
Create a script with following content
connect &1
spool C:\ABC
#c:\ABC
spool off;
and run it
#your_script_name
BTW: there is no reason to run script c:\ABC while you are spooling into it. What exactly do you want to achieve?
exec[ute] is SQL*Plus and SQL Developer (and maybe other clients) shorthand for an anonymous block. It is a client command, it is not part of PL/SQL. You are trying to use it inside a PL/SQL declare section, where it is not valid or recognised.
If you want a client bind variable you need the var[iable] command:
var schemaname varchar2(20);
exec :schemaname := '&1';
BEGIN
...
Notice the single quotes around &1, as it's being assigned to a string variable.
But you can't connect inside a PL/SQL block either, and you can't use a bind variable for the connection.
connect :schemaname
will prompt for a password (even if you defined it's value as user/passwd) and try to connect as a user lieterally called :schemaname.
You can use a substituion variable, but you don't really need to define a new one; as you seem to be passing the credentials in, you can do:
connect &1
(without surrounding quotes)

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

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

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()?

Creating an Oracle Stored Procedure and Executing it from .sql file

I have two .sql files both are Oracle stored procedures which both take in input parameters. I would like to first connect to a remote oracle database using sqlplus in command line and want to first use both files to create their respective stored procedures so I see them under procedures for that connection in Oracle SQL Developer.
After this I have two more .sql files which look like this and are designed to take input parameters and execute the stored procedures. This is one of the files that is meant to execute the stored procedure "REPORT".
DECLARE
NAME VARCHAR2(200);
VERSION VARCHAR2(200);
STARTDATE DATE;
ENDDATE DATE;
BEGIN
NAME := '&1';
VERSION := '&2';
STARTDATE := '&3';
ENDDATE := '&4';
exec REPORT(NAME, VERSION, STARTDATE, ENDDATE);
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20101,SQLERRM);
END;
/
In command prompt I first try to create the stored procedure in the database by:
C:\Users\Desktop>sqlplus username/password #report_setup.sql
When I try this the output get is just empty lines that are numbered and beginning at the number that is 1 greater then the last line of my .sql file. My report_setup.sql file is 81 lines long and the output of the sqlplus command is blank numbered lines beginning at 83.
Please let me know how I can create and execute these stored procedures properly through sqlplus.
Thanks in advance,
I think you have to remove the 'exec'-word, and it's crucial to have the slash at the bottom at the very start of the line, with no spaces in front of it:
DECLARE
NAME VARCHAR2(200);
VERSION VARCHAR2(200);
STARTDATE DATE;
ENDDATE DATE;
BEGIN
NAME := '&1';
VERSION := '&2';
STARTDATE := '&3';
ENDDATE := '&4';
REPORT(NAME, VERSION, STARTDATE, ENDDATE);
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20101,SQLERRM);
END;
/
It would have been more useful to show the report_setup.sql than the script that calls the procedure it creates... but from the symptoms you describe, the report_setup.sql doesn't have a / at the end of the procedure declaration.
It presumably has something like:
CREATE OR REPLACE PROCEDURE REPORT(NAME VARCHAR2, VERSION VARCHAR2,
STARTDATE DATE, ENDDATE DATE) AS
...
BEGIN
...
END REPORT;
It needs to have
...
BEGIN
...
END REPORT;
/
Since you're running it from the command line with # it should also have an EXIT at the end; but without the / that will be treated as part of the procedure, which is never compiled.
You can suppress the line number display, incidentally, by calling SQL*Plus with the -s flag - though at the moment they are useful since they show roughly what the problem is.
I had a similar issue. The problem was the encoding used, sqlplus expects UTF-8 standard enconding, wherever different encoding cause weird behavior.

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