PL/SQL Packages inserting count Number autmomatically in variable - oracle

the Exercise is:
Create a public variable in a package called v_Guest_Count
that is automatically initialised with the number of
Guests in the Guests table. Use the following SQL:
SELECT COUNT(*)
FROM Guests;
I tried it like this but it won't work:
create or replace PACKAGE BODY BEACHCOMBER IS
v_guest_count NUMBER;
BEGIN
SELECT COUNT (*) FROM A2_GUESTS
INTO v_guest_count;
END BEACHCOMBER;
Thank you
Edit: This is the testing code:
PROMPT
PROMPT TESTING: Initialisation of the v_Guest_Count variable. Expect 81.
BEGIN
DBMS_OUTPUT.PUT_LINE('v_Guest_Count has been initialised to: '||TO_CHAR(BEACHCOMBER.v_Guest_Count));
END;

You have A LOT of stuff wrong with your PL/SQL. I have modified the code below.
If you want to return a scalar result from a query, you either need an OUT parameter on the procedure, or create a function to return the value.
Syntax for "select into" is wrong.
You cannot access the value of a locally-scoped variable (v_guest_count) outside of the function/procedure.
create or replace FUNCTION BEACHCOMBER_COUNT
RETURN NUMBER
IS
v_guest_count NUMBER;
BEGIN
SELECT COUNT (*) INTO v_guest_count
FROM dual; -- A2_GUESTS;
RETURN v_guest_count;
END;
PROMPT PROMPT TESTING: Initialisation of the v_Guest_Count variable. Expect 81.
BEGIN
DBMS_OUTPUT.PUT_LINE('v_Guest_Count has been initialised to: '||TO_CHAR(BEACHCOMBER_COUNT()));
END;
/
I would suggest getting a good pl/sql book.

Related

How to call a stored procedure in pl/sql developer

I am new at this and have a simple question.
I have created a procedure like so in pl/sql developer
CREATE OR REPLACE PROCEDURE myproc2 AS
BEGIN
SELECT cd_desc des, cd_value cd FROM v_codes WHERE cd_type='CVS02'
END;
Now I want to call the procedure and see the output however when I run this
BEGIN
myproc2;
END;
in Pl/sql I am getting an error saying object myproc2 is invalid
How do I call a stored procedure in PL/SQL?
You're calling it right, but the procedure is wrong. If you check its status, it is invalid.
In PL/SQL, a SELECT requires INTO:
CREATE OR REPLACE PROCEDURE myproc2 AS
l_cd_desc v_codes.cd_desc%type;
l_cd_value v_codes.cd_value%type;
BEGIN
SELECT v.cd_desc, v.cd_value
INTO l_cd_desc, l_cd_value
FROM v_codes v
WHERE v.cd_type = 'CVS02';
END;
Beware of possible NO_DATA_FOUND or TOO_MANY_ROWS exception.
Also, although it'll now run OK (I guess), you won't see anything because it is unknown what you'll do next. You could, for example, choose to display values you fetched. In that case, add
<snip>
WHERE v.cd_type = 'CVS02';
dbms_output.put_line(l_cd_desc ||', '|| l_cd_value);
END;
Don't forget to enable serveroutput.
As you commented, you got too_many_rows. How to handle it? It depends on what you want to do. One option is to switch to a cursor FOR loop; now you don't need local variables and - as there's no SELECT statement itself - no INTO clause either:
CREATE OR REPLACE PROCEDURE myproc2
AS
BEGIN
FOR cur_r IN (SELECT v.cd_desc, v.cd_value
FROM v_codes v
WHERE v.cd_type = 'CVS02')
LOOP
DBMS_OUTPUT.put_line (cur_r.cd_desc || ', ' || cur_r.cd_value);
END LOOP;
END;
One great thing about Oracle SQL Developer is the GUI and that it does things for you.
You can open a sheet and run it the traditional way:
BEGIN
PROCEDURENAME(PARAM);
END;
or you can use the GUI, find the object with the (View->) Find DB object, find it, click on it and use the green arrow in the toolbar. It will open a UI for any parameters you used within the procedure.
In SQL Developer, if you want to see the output then you can return a cursor:
CREATE OR REPLACE PROCEDURE myproc2(
o_cursor OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN o_cursor FOR
SELECT cd_desc AS des,
cd_value AS cd
FROM v_codes
WHERE cd_type='CVS02'; -- You need a ; statement terminator here.
END;
/
Then you can use:
-- Declare a cursor bind variable
VARIABLE cur SYS_REFCURSOR;
BEGIN
-- Call the cursor outputting into the bind variable.
myproc2(:cur);
END;
/
-- Print the cursor
PRINT :cur;
And run it as a script (using F5).

Oracle Packages and using a select statement in a public variable

Have been searching for ages to no avail. Part of an assessment it specifies that we must declare a public variable WITHIN a package (so don't try telling me to make it a stand alone function...) that is the number of rows from another table ("SELECT COUNT(*) FROM A2_GUESTS" is the hint)
I can set a public variable easily enough as a static number, however if i try to add the select statement it throws an error.
If I try to assign it in the package body then it also throws an error, if I wrap it within "begin" and "end" it terminates the package body too early.
CREATE OR REPLACE PACKAGE Beachcomber
AS
v_Guest_Count NUMBER := 0;
END Beachcomber;
/
CREATE OR REPLACE PACKAGE BODY Beachcomber IS
SELECT COUNT(*) INTO v_Guest_Count FROM A2_GUESTS; -- doesn't work
v_Guest_Count NUMBER := SELECT COUNT(*) FROM A2_GUESTS; -- doesn't work
BEGIN
v_Guest_Count NUMBER := SELECT COUNT(*) FROM A2_GUESTS;
END; -- doesn't work - ends the package prematurely
END Beachcomber;
the above example are the ways i've been trying (amongst others), not at the same time but individually.
We get given the code to test it: (must not change this testing code)
PROMPT
PROMPT TESTING: Initialisation of the v_Guest_Count variable. Expect 81.
BEGIN
DBMS_OUTPUT.PUT_LINE('v_Guest_Count has been initialised to: '||TO_CHAR(BEACHCOMBER.v_Guest_Count));
END;
any help is greatly appreciated, i found someone asked this here once back in 2015 but the only answer was given as make it a function and they adjusted the testing code so thats less than helpful.
there is more code within the package with procedures and functions:
CREATE OR REPLACE PACKAGE Beachcomber
IS
v_Guest_Count NUMBER := 0;
PROCEDURE ADD_GUEST
(p_guest_name A2_GUESTS.guest_name%TYPE,
p_guest_address A2_GUESTS.guest_address%TYPE);
END Beachcomber;
/
CREATE OR REPLACE PACKAGE BODY Beachcomber IS
BEGIN
SELECT COUNT(*) INTO v_Guest_Count FROM A2_GUESTS;
PROCEDURE ADD_GUEST
(p_guest_name A2_GUESTS.guest_name%TYPE,
p_guest_address A2_GUESTS.guest_address%TYPE)
IS BEGIN
INSERT INTO A2_GUESTS (Guest_ID, Guest_Name, Guest_Address)
VALUES (guest_id_seq.NEXTVAL, p_guest_name, p_guest_address);
v_Guest_Count := v_Guest_Count +1;
END ADD_GUEST;
END Beachcomber;
this will throw:
5/5 PLS-00103: Encountered the symbol "PROCEDURE" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge The symbol "declare" was substituted for "PROCEDURE" to continue.
im normally alright with working it out from the error messages but oracle error messages may as well be written in dutch to me :/
We can include initialising code in a package by putting it at the end of the body. It takes the form of a BEGIN block which is terminated by the final END of the package body.
create or replace package BEACHCOMBER is
v_Guest_Count pls_integer;
function get_cnt return number;
end BEACHCOMBER;
/
create or replace package body BEACHCOMBER is
function get_cnt return number
is
begin
return v_Guest_Count;
end get_cnt;
<< init_block >>
begin
select count(*)
into v_Guest_Count
from A2_GUESTS;
end BEACHCOMBER;
/
The code under the label << init_block >> is run the first time the package is invoked. This includes referencing the public variable. This code not run again in the session, unless the package is recompiled, which discards state.
Here is my test script. I have published this as a working demo on Oracle LiveSQL (because DBMS_OUTPUT) but you need a free Oracle account to run it. Check it out
Test set up
drop table A2_GUESTS
/
create table A2_GUESTS (id number);
insert into A2_GUESTS select level from dual connect by level <=23;
create or replace package BEACHCOMBER is
v_Guest_Count pls_integer;
function get_cnt return number;
end BEACHCOMBER;
/
create or replace package body BEACHCOMBER is
function get_cnt return number
is
begin
return v_Guest_Count;
end get_cnt;
begin
select count(*)
into v_Guest_Count
from A2_GUESTS;
end BEACHCOMBER;
/
Here are the tests;
begin
dbms_output.put_line('count = ' || BEACHCOMBER.v_Guest_Count);
end;
/
insert into A2_GUESTS values (42)
/
select BEACHCOMBER.get_cnt
from dual
/
alter package BEACHCOMBER compile body
/
select BEACHCOMBER.get_cnt
from dual
/
You have to set the Package variable in the package body. You need not declare another variable locally in the body.
CREATE OR REPLACE PACKAGE BODY Beachcomber IS
BEGIN
SELECT COUNT(*) INTO v_Guest_Count FROM A2_GUESTS;
END Beachcomber;
/
You may then access that variable in any other PL/SQL block.
SET SERVEROUTPUT ON
BEGIN
DBMS_OUTPUT.PUT_LINE(Beachcomber.v_Guest_Count);
end;
/
0
PL/SQL procedure successfully completed.
EDIT
You should put the queries inside the procedure as you would be calling the procedure externally.
CREATE OR REPLACE PACKAGE BODY beachcomber IS
PROCEDURE add_guest (
p_guest_name a2_guests.guest_name%TYPE,
p_guest_address a2_guests.guest_address%TYPE
)
IS
BEGIN
SELECT COUNT(*)
INTO v_guest_count
FROM a2_guests;
INSERT INTO a2_guests (
guest_id,
guest_name,
guest_address
) VALUES (
guest_id_seq.NEXTVAL,
p_guest_name,
p_guest_address
);
v_guest_count := v_guest_count + 1;
END add_guest;
END beachcomber;
/
EDIT2 : using a main procedure for initialisation.
CREATE OR REPLACE PACKAGE beachcomber IS
v_guest_count NUMBER := 0;
PROCEDURE main;
PROCEDURE add_guest (
p_guest_name a2_guests.guest_name%TYPE,
p_guest_address a2_guests.guest_address%TYPE
);
END beachcomber;
/
CREATE OR REPLACE PACKAGE BODY beachcomber IS
PROCEDURE add_guest (
p_guest_name a2_guests.guest_name%TYPE,
p_guest_address a2_guests.guest_address%TYPE
)
IS
BEGIN
INSERT INTO a2_guests (
guest_id,
guest_name,
guest_address
) VALUES (
guest_id_seq.NEXTVAL,
p_guest_name,
p_guest_address
);
v_guest_count := v_guest_count + 1;
END add_guest;
PROCEDURE main
IS
BEGIN
SELECT COUNT(*)
INTO v_guest_count
FROM a2_guests;
END main;
END beachcomber;
/
Execution of procedure.
BEGIN
beachcomber.main;
beachcomber.add_guest('Sherlock','221b baker street');
END;
/

Oracle PL/SQL array input into parameter of pipelined function

I am new to PL/SQL. I have created a pipelined function inside a package which takes as its parameter input an array of numbers (nested table).
But I am having trouble trying to run it via an sql query. Please see below
my input array
CREATE OR REPLACE TYPE num_array is TABLE of number;
my function declaration
CREATE OR REPLACE PACKAGE "my_pack" as
TYPE myRecord is RECORD(column_a NUMBER);
TYPE myTable IS TABLE of myRecord;
FUNCTION My_Function(inp_param num_array) return myTable PIPELINED;
end my_pack;
my function definition
CREATE OR REPLACE PACKAGE BODY "my_pack" as
FUNCTION My_Function(inp_param num_array) return myTable PIPELINED as
rec myRecord;
BEGIN
FOR i in 1..inp_param.count LOOP
FOR e IN
(
SELECT column_a FROM table_a where id=inp_param(i)
)
LOOP
rec.column_a := e.column_a;
PIPE ROW (rec);
END LOOP;
END LOOP;
RETURN;
END;
end my_pack;
Here is the latest code I've tried running from toad. But it doesn't work
declare
myarray num_array;
qrySQL varchar2(4000);
begin
myarray := num_array(6341,6468);
qrySQL := 'select * from TABLE(my_pack.My_Function(:myarray))';
execute immediate qrySQL;
end;
So my question is how can I feed an array into this pipelined function from either TOAD or SQL Developer. An example would be really handy.
Thanks
The error is fairly clear, you have a bind variable that you haven't assigned anything to. You need to pass your actual array with:
qrySQL := 'select * from TABLE(my_pack.My_Function(:myarray))';
execute immediate qrySQL using myarray;
It's maybe more useful, if you want to call it from PL/SQL, to use static SQL as a cursor:
set serveroutput on
declare
myarray num_array;
begin
myarray := num_array(6341,6468);
for r in (select * from TABLE(my_pack.My_Function(myarray))) loop
dbms_output.put_line(r.column_a);
end loop;
end;
/
Or just query it statically as a test, for fixed values:
select * from TABLE(my_pack.My_Function(num_array(6341,6468)));
SQL Fiddle with some minor tweaks to the function to remove errors I think came from editing to post.

How can I test a function working or not in pl-sql?

I learned the basics of writing a function and procedure in pl-sql but I don't know how to test if it's working , and if not How can I debug it .
Any Ideas please .
thanks all.
Here is the function I'm trying to test it
CREATE OR REPLACE FUNCTION MIN_MAX_SAL RETURN NUMBER AS
cursor emp_cur is select salary from employees ;
emp_sal number;
min_sal jobs.min_salary%type;
max_sal jobs.max_salary%type;
BEGIN
select min_salary , max_salary into min_sal , max_sal from jobs;
for emp_sal in emp_cur loop
if (emp_sal > max_sal or emp_sal < min_sal) then
return 0;
end loop;
RETURN 1;
END MIN_MAX_SAL;
Any help ?
In general, like the question - how to run/test in SQL*Plus...
To test a function that takes scalar arguments and returns a scalar value:
SELECT function_name(parm1, parm2) FROM DUAL;
To test a procedure:
EXEC procedure_name(parm1, parm2)
If the procedure returns a REFCURSOR or SYS_REFCURSOR by way of an OUT parameter:
VAR x REFCURSOR
EXEC procedure_name(parm1, parm2, :x)
PRINT x
The colon before the x in the second line above is required. It's not allowed in the other two lines (VAR and PRINT).
If you're having trouble with testing a specific function or procedure in SQL*Plus, please post the function/proc or at the very least its declaration.
To debug, sprinkle DBMS_Output.Put_Line calls at places where you want to check values. The DBMS_Output package is documented here. Before running a proc with DBMS _Output calls, type the following at the SQL*Plus command line:
SET SERVEROUTPUT ON SIZE 50000
The SIZE is the number of characters that Oracle will allow DBMS_Output to echo. All output is sent back after the procedure is finished.

Calling a stored PROCEDURE in Toad

I have a defined a new stored procedure but get a error while calling it,
CREATE OR REPLACE PROCEDURE SCOTT.getempsal(
p_emp_id IN NUMBER,
p_emp_month IN CHAR,
p_emp_sal OUT INTEGER)
AS
BEGIN
SELECT EMP_SAL
INTO p_emp_sal
FROM EMPLOYEE_SAL
WHERE EMP_ID = p_emp_id
AND EMP_MONTH = p_emp_month;
END getempsal;
And trying to call it:
getempsal(1,'JAN',OUT) --Invalid sql statement.
Your procedure contains an out parameter, so you need to call it in block like:
declare
a number;
begin
getempsal(1,'JAN',a);
dbms_output.put_line(a);
end;
A simple procedure (let's say with a number parameter) can be called with
exec proc(1);
or
begin
proc(1);
end;
Just write EXECUTE procedure_name('provide_the_valueof_IN parameter','value of in parameter', :k) ;
Run this statement a popup will come set the parameters as in out and the datatype too. U will see the output in another popup window.

Resources