How call procedure inside in another procedure in Oracle, Sql Developer? - sql

CREATE OR REPLACE PROCEDURE ShowShips3Task(
p_Register IN ship.registry_country%TYPE,
o_name OUT ship.ship_name%TYPE,
o_capitan OUT ship.captain_name%TYPE)
IS
procedure showshipsDisp(
o_cap out Ship.captain_name%type,
o_dis out Ship.displacement%type)
is
begin
Select Captain_name, Displacement
into o_cap, o_dis
from Ship Where Ship_name = 'Avrora';
end;
BEGIN
SELECT Ship_name , Captain_Name
INTO o_name, o_capitan
from Ship WHERE registry_country LIKE p_register || '%';
END;
how execute one Procedure inside another in same time?
and how can i create multivalued paramater, means that second proceduru inside depend on paramatr of first procedure?

In the example from the question nested procedure is only declared but never called. To run the nested procedure the call has to be present between BEGIN and END statements:
BEGIN
SELECT Ship_name , Captain_Name
INTO o_name, o_capitan
from Ship WHERE registry_country LIKE p_register || '%';
showshipsDisp(o_cap => ?
,o_dis => ?);
END;
Question marks should be replaced by proper variables.

Related

Execute immediate select returns no values

I have select statement
select name, surname
from student
where id_student = 1;
It returns
name surname
Bob Smith
I want to create procedure with same select statement, using execute immediate:
create or replace procedure select_procedure
as
begin
execute immediate
'select name, surname
from student
where id_student = 1';
end;
/
exec select_procedure;
When this procedure is executed it shows PL/SQL procedure successfully completed. How do I get the result? (set serveroutput is on)
You have to select into something. If you don't then the query isn't even executed (though it is parsed).
create or replace procedure select_procedure
as
l_name student.name%TYPE;
l_surname student.name%TYPE;
begin
execute immediate
'select name, surname
from student
where id_student = 1'
into l_name, l_surname;
end;
/
But, in no particular order: (a) you should use bind variables instead of having the literal value 1 embedded in the dynamic statement; (b) this doesn't need to be dynamic at all; and (c) the caller won't be able to see the values returned by the query anyway - unless you select into OUT arguments instead, or display them with dbms_output() (although that should really only be used for debugging as you can't control whether the client will show it).
So you could do:
create or replace procedure select_procedure
as
l_name student.name%TYPE;
l_surname student.name%TYPE;
begin
select name, surname
into l_name, l_surname
from student
where id_student = 1;
dbms_output.put_line('name=' || l_name ||', surname=' || l_surname);
end;
/
or
create or replace procedure select_procedure (
p_name OUT student.name%TYPE,
p_surname OUT student.name%TYPE
)
as
begin
select name, surname
into p_name, p_surname
from student
where id_student = 1;
end;
/
and have your caller pass in its own variable names to populate, and then do whatever it needs with those. The caller would usually also pass in the ID you're looking for, so you don't have the 1 hard-coded.
It doesn't seem like a procedure is really the best mechanism for this though.
Also, using a select ... into (static or dynamic) will error if the query returns zero rows or more than one row. It will only work if there is exactly one row returned. A cursor would handle any number of rows - but unless you are just printing the results (as #Jayanth shows) you need to pass the cursor back to the caller instead. You could do a bulk collect into a collection instead, but you still have to do something with that.
You have to write a cursor for this.Please find below the syntax for the same.
Syntax:
create or replace procedure select_procedure
as
CURSOR <cursor_name> IS <SELECT statement without semicolon>;
BEGIN
FOR record IN <cursor_name>
LOOP
Dbms_output.put_line(‘Record Fetched:‘||record.name);
Dbms_output.put_line(‘Record Fetched:‘||record.surname);
END LOOP;
END;

IF statement using procedure parameters?

I’m wondering if it’s technically possible to use procedure parameters in IF statement or how to solve this problem in different manner.
Situation description:
I have a procedure within other procedure where arguments of inner procedure are parameters of outer procedure. I would
like to use parameters of inner procedure within it’s body in IF statement eg: IF parameter1 OR parameter2 OR parameter3 IS NOT NULL THEN. . It’s worth to be mentioned that all parameters of outer procedure have to be DEFAULT NULL. Any ideas? Cheers.
are you trying to do like this :
--first procedure
CREATE OR REPLACE PROCEDURE p1(f_name varchar2 ,sal NUMBER )
IS
BEGIN
p2(f_name,sal);
END;
--second procedure
CREATE OR replace PROCEDURE p2(f_name varchar2 ,sal NUMBER )
IS
BEGIN
IF f_name IS NOT NULL OR sal IS NOT NULL
THEN
dbms_output.put_line(f_name ||' '||sal);
END IF;
END;
then call the first procedure :
BEGIN
p1( 'john',null );
END;

SQL - Oracle Functions using variables for schema names

I am writing some oracle stored procedures where we have conditional logic which effects which schema we are working from and I am not sure how to do this in the sql for the stored proc. If I am working with prepared statements then its fine but in the scenario where I am just executing a query to say populate another variable then I dont know how to do this. For example
PROCEDURE register (
incustomer_ref in VARCHAR2,
incustomer_type in VARCHAR2,
outreturn_code out VARCHAR2
)
IS
customer_schema varchar2(30);
record_exists number(1);
BEGIN
if incustomer_type='a' then
customer_schema:='schemaA';
elsif incustomer_type='b' then
customer_schema:='schemaB';
end if;
--This type of command I cant get to work
select count(*) into record_exists from **customer_schema**.customer_registration where customer_ref=incustomer_ref
--but a statement like this i know how to do
if record_exists = 0 then
execute immediate 'insert into '||customer_schema||'.customer_registration
values ('||incustomer_ref||','Y',sysdate)';
end if;
Can anyone shine some light on what I am missing here.
Cheers
you can use execute immediate also for select statment:
execute immediate 'select count(*) from '|| customer_schema
|| '.customer_registration where customer_ref= :b1'
into record_exists using incustomer_ref;

Basic Oracle question

I am new to oracle. When I create a stored procedure using:
CREATE OR REPLACE PROCEDURE PROCEDURE1
AS
BEGIN
SELECT FIRSTNAME,
LASTNAME
INTO FirstName,LastName
FROM EMPLOYEE;
END PROCEDURE1;
i get the following errors:
PL/SQL Statement Ignored
Identifier FIRSTNAME must be declared
ORA-00904 Invalid identifier
You need to declare variables before you attempt to populate them:
CREATE OR REPLACE PROCEDURE PROCEDURE1
AS
FirstName EMPLOYEE.FIRSTNAME%TYPE;
LastName EMPLOYEE.LASTNAME%TYPE;
BEGIN
SELECT FIRSTNAME,
LASTNAME
INTO FirstName,LastName
FROM EMPLOYEE;
END PROCEDURE1;
The %TYPE notation is shorthand for data type declaration that matches the column data type. If that data type ever changes, you don't need to update the procedure.
You need to declare the variables.
CREATE OR REPLACE
PROCEDURE PROCEDURE1 AS
V_FIRSTNAME VARCHAR2(60);
V_LASTNAME VARCHAR2(60);
BEGIN
SELECT FIRSTNAME,LASTNAME
INTO V_FIRSTNAME ,V_LASTNAME
FROM EMPLOYEE;
END PROCEDURE1;
In reply to your comment, SQL statements in PL/SQL block can fetch only 1 record. If you need to fetch multiple records, you will need to store the records in a cursor and process them.
CREATE OR REPLACE
PROCEDURE PROCEDURE1 AS
CURSOR EMP_CUR IS
SELECT FIRSTNAME,LASTNAME
FROM EMPLOYEE;
EMP_CUR_REC EMP_CUR%ROWTYPE;
BEGIN
FOR EMP_CUR_REC IN EMP_CUR LOOP
-- do your processing
DBMS_OUTPUT.PUT_LINE('Employee first name is ' || EMP_CUR_REC.FIRSTNAME);
DBMS_OUTPUT.PUT_LINE('Employee last name is ' || EMP_CUR_REC.LASTNAME);
END LOOP;
END PROCEDURE1;
To explain:
EMP_CUR holds the SQL statement to be executed.
EMP_CUR_REC holds the records that will be fetched by the SQL statement.
%ROWTYPE indicates that the Record will be of the same data type as the row which holds the data
The FOR LOOP will fetch each record, and you can do whatever processing that needs to be done.
I think the "AS" keyword won't work. If it doesn't work, then use "IS".
Rest are fine and very good tips.
If you need any help regarding PL/SQL, then you can have a look at this link. It is very simple and easy to understand;
http://plsql-tutorial.com/
This is my solution to the error which you are getting;
CREATE OR REPLACE PROCEDURE PROCEDURE1 IS
v_FIRSTNAME EMPLOYEE.FIRSTNAME%TYPE;
v_LASTNAME EMPLOYEE.LASTNAME%TYPE;
CURSOR EMPCURSOR IS
SELECT FIRSTNAME, LASTNAME FROM EMPLOYEE;
BEGIN
IF NOT EMPCURSOR%ISOPEN THEN
OPEN EMPCURSOR;
END IF;
LOOP
FETCH EMPCURSOR INTO V_FIRSTNAME,V_LASTNAME;
EXIT WHEN EMPCURSOR%NOTFOUND;
END LOOP;
IF EMPCURSOR%ISOPEN THEN
CLOSE EMPCURSOR;
END;
END PROCEDURE1;
You can also use DBMS_OUTPUT.PUT_LINE(V_FIRSTNAME || ','|| V_LASTNAME), inside the loop to display the output. but in order to do that, you first need to execute the command server output on
In a response to #Sathya's answer above #kayak asked "Can i have something like Select * from Tablename or select firstname,lastname from tablename , like we have in sql server".
Yes, you can do that, but you'll either need to include a WHERE clause or use a cursor. If you include a WHERE clause which limits your results to a single row you could write something like
CREATE OR REPLACE PROCEDURE PROCEDURE1
IS
rowEmployees EMPLOYEE%ROWTYPE;
BEGIN
SELECT *
INTO rowEmployees
FROM EMPLOYEE
WHERE EMPLOYEE_ID = 12345;
END PROCEDURE1;
On the other hand, if you either don't have a WHERE clause because you wish to process all rows in the table, or you have a WHERE clause which doesn't limit your results to a single row you could use a cursor in the following manner:
CREATE OR REPLACE PROCEDURE PROCEDURE1 IS
BEGIN
FOR rowEmployees IN (SELECT *
FROM EMPLOYEE
WHERE EMPLOYEE_ID IN (12345, 67890, 111213, 141516))
LOOP
<do something with rowEmployees here>
END LOOP;
END PROCEDURE1;
Share and enjoy.

Oracle Stored Procedure with Alter command

I am trying to build an Oracle stored procedure which will accept a table name as a parameter. The procedure will then rebuild all indexes on the table.
My problem is I get an error while using the ALTER command from a stored procedure, as if PLSQL does not allow that command.
Use the execute immediate statement to execute DDL inside PL/SQL.
create procedure RebuildIndex(index_name varchar2) as
begin
execute immediate 'alter index ' || index_name || ' rebuild';
end;
I tested this code; it works.
Documentation.
Passing Schema Object Names As Parameters
Suppose you need a procedure that
accepts the name of any database
table, then drops that table from your
schema. You must build a string with a
statement that includes the object
names, then use EXECUTE IMMEDIATE to
execute the statement:
CREATE TABLE employees_temp AS SELECT last_name FROM employees;
CREATE PROCEDURE drop_table (table_name IN VARCHAR2) AS
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ' || table_name;
END;
/
Use concatenation to build the string,
rather than trying to pass the table
name as a bind variable through the
USING clause.
In addition, if you need to call a
procedure whose name is unknown until
runtime, you can pass a parameter
identifying the procedure. For
example, the following procedure can
call another procedure (drop_table) by
specifying the procedure name when
executed.
CREATE PROCEDURE run_proc (proc_name IN VARCHAR2, table_name IN VARCHAR2) ASBEGIN
EXECUTE IMMEDIATE 'CALL "' || proc_name || '" ( :proc_name )' using table_name;
END;
/
If you want to drop a table with the
drop_table procedure, you can run the
procedure as follows. Note that the
procedure name is capitalized.
CREATE TABLE employees_temp AS SELECT last_name FROM employees;
BEGIN
run_proc('DROP_TABLE', 'employees_temp');
END;
/
Here are a couple of possibilities. First, you would have to treat the SQL as dynamic SQL. Second, Oracle DDL statements cannot be run in a transaction (or, they terminate the current transaction and cannot themselves be rolled back). This may affect whether you can use them in stored procedures, or where you can use stored procedures that contain them.
If none of the above apply at all - there could easily be something else astray - I suggest posting some code.