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)
Related
I have a shell script that calls an Oracle Stored Procedure. The SP has two parameters - the first is of type VARCHAR2 and the second is of type DATE
CREATE OR REPLACE PROCEDURE MY_SCHEMA.MY_SP_NAME(firstParameter IN VARCHAR2, dateParameter IN DATE)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Successfully called Procedure');
END;
/
In my shell script, I'm trying to execute the procedure using the following command:
echo "EXECUTE MY_SCHEMA.MY_SP_NAME('TEST', '20170909') " | $ORACLE_HOME/bin/sqlplus $ORAUSER/$ORAPASS
The problem is that when the script runs I get the following error: ORA-01861: literal does not match format string. My guess is that there is an issue with the '20170809' value that I'm passing to the date parameter but I'm unsure how to resolve this. Any help is appreciated.
(PS: The ORACLE_HOME/USER/PASS environment variables are all set correctly and I can successfully run SQLPLUS from the script so there are no problems connecting to the Oracle database)
You can try to use the to_date function:
Execute my_schema.my_sp_name(‘test’,to_date(‘20170909’, ‘yyyymmdd’))
Or use ISO date format in your date parameter.
I've made this program and I was wondering why oracle prompts for input even when it does not run the 'D' case (when 'A' is imputed for example).
SET SERVEROUTPUT ON;
ACCEPT p_user_letter PROMPT 'Enter an option';
DECLARE
v_user_letter VARCHAR2(200) := UPPER('&p_user_letter');
BEGIN
CASE v_user_letter
when 'A' then dbms_output.put_line('A pressed');
when 'D' then new_customer('&userEntered');
else dbms_output.put_line('Other');
END CASE;
END;
/
CREATE OR REPLACE PROCEDURE new_customer
(ccName IN Varchar2)
IS
BEGIN
dbms_output.put_line('Ran procedure');
END new_customer;
From the error message it seems like it runs a new and old version of declare which forces all uninitialized prompts to have a value, but i'm not certain and could not find out why online.
Both new and old running
('&userEntered'); is a substitution variable.
The substitution variables are not a part of SQL, this is a feature of SQL-Plus client, it is also supported by SQL-Developer.
When you hit Enter (or Run icon in SQL-Developer), SQL-Plus first analyses your script. When it finds &xxx string in your script, then prompts the user for a value. When the user enters the value then SQL-Plus substitutes (replaces) &xxx with the value entered by the user.
When SQL-Plus substitutes all substitution variables, then it starts to execute this script - that is, it sends SQL commands from the script to the Oracle Database for execution.
You can think of the variable substitution in SQL-Plus as a kind of macro preprocesing.
I have a Sqlplus script that I need to execute as part of a process chain, and its purpose is to get rid of two user-defined objects:
myscript.sql
def tablespaceName=&1
drop type &tablespaceName.my_user_tab;
commit;
drop type &tablespaceName\.my_user_type;
commit;
/
Execution: Sqlplus myDbUser/myDbPassword#myDbSID #myscript.sql TESTTABLESPACE
The Sqlplus engine is somehow losing the dot character that separates the tablespace from the object name:
old 1: drop type &tablespaceName.my_user_tab
new 1: drop type TESTTABLESPACEmy_user_tab
drop type TESTTABLESPACEmy_user_tab
*
ERROR at line 1:
ORA-04043: object TESTTABLESPACEMY_USER_TAB does not exist
How do I get Sqlplus to honor the dot and stop removing it from the script?
First of all, you don't need commit/rollback for DDLs.
And to escape the dots. Just use double dots.
drop type &tablespaceName..my_user_tab;
From Doc
If you wish to append characters immediately after a substitution
variable, use a period to separate the variable from the character.
Can any one please tell me how to execute a simple oracle stored procedure having out parameter inside a shell script.That means it should return a value into the unix environment.
I assume you want to start a script using SQLPLUS. This answer explains how to assign the value of an out parameter to a bind variable in SQLPLUS.
Call stored procedure from sqlplus
You can exit sqlplus with this value and use that value in the calling script.
exit x
But this usually is restricted to numerical values in a limited range.
There are a number of ways, but the one I tend to use is illustrated below.
The sqlplus script the_sql_script.sql
var ret varchar2(2000)
exec the_procedure ( the_out_param => :ret );
set pages 0 head off lines 200 trimspool on
spool sqlplus.return
select 'RETURN_VALUE=' || :ret FROM dual;
spool off
quit
In shell:
sqlplus / # the_sql_script.sql
. ./sqlplus.return
echo $RETURN_VALUE
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