declaring pl sql variable using query then using in subsequent query - oracle

I’ve read some on declaring and using variables in PL/SQL. and I’ve only done so in other versions (TSQL) or code languages.
Below is what I’m trying to do, which is
to declare a variable
assign a value to that variable via query
use the subsequent result from #2
in another query.
I’ve tried other methods listed on the Internet but nothing I do seems to work when calling the variable in the final query.
The declaration and into statements work but the last select query does not.
declare
Degr_term varchar2(20);
begin
select max(z.term)
INTO degr_term
from dwh.rpt_ersd_vw d
join dwh.dim_ers_term_vw z
on d.DIM_DEGR_ERS_TERM_SKEY = z.dim_ers_term_skey;
select * from ir_wip.stem_enr s where s.min_deg_term = degr_term;
end;

Just like you selected INTO from the 1st select statement, you have to do it in the 2nd as well. It means that you'll have to declare a variable which will hold its contents.
Presuming - maybe not correctly - that 2nd select returns only one row - you could
SQL> declare
2 degr_term varchar2(20);
3 l_stem stem_enr%rowtype; --> this
4 begin
5 select max(z.term)
6 into degr_term
7 from rpt_ersd_vw d
8 join dim_ers_term_vw z
9 on d.DIM_DEGR_ERS_TERM_SKEY = z.dim_ers_term_skey;
10
11 select *
12 into l_stem --> this
13 from stem_enr s
14 where s.min_deg_term = degr_term;
15 end;
16 /
PL/SQL procedure successfully completed.
SQL>
(I removed schema names as I don't have them and didn't feel like creating ones.)
If the 2nd query returns more than a single row, then you'd e.g.
SQL> declare
2 degr_term varchar2(20);
3 type l_stem_typ is table of stem_enr%rowtype;
4 l_stem_tab l_stem_typ;
5 begin
6 select max(z.term)
7 into degr_term
8 from rpt_ersd_vw d
9 join dim_ers_term_vw z
10 on d.DIM_DEGR_ERS_TERM_SKEY = z.dim_ers_term_skey;
11
12 select *
13 bulk collect
14 into l_stem_tab
15 from stem_enr s
16 where s.min_deg_term = degr_term;
17 end;
18 /
PL/SQL procedure successfully completed.
SQL>
[EDIT: How to output the result? Using a loop]
Presume that table looks like this (I don't know really, you never posted any sample data):
SQL> select * from stem_enr;
MIN_DEG_TERM NAME SURN
------------ ------ ----
1 Little Foot
1 Big Foot
Then you'd (simplified example; I didn't feel like creating other tables as well):
SQL> declare
2 type l_stem_typ is table of stem_enr%rowtype;
3 l_stem_tab l_stem_typ;
4 begin
5 select *
6 bulk collect
7 into l_stem_tab
8 from stem_enr s
9 where s.min_deg_term = 1;
10
11 for i in 1 .. l_stem_tab.count loop
12 dbms_output.put_line(l_stem_tab(i).name ||' '|| l_stem_tab(i).surname);
13 end loop;
14 end;
15 /
Little Foot
Big Foot
PL/SQL procedure successfully completed.
SQL>

Related

How to call a variable inside a procedure in plsql?

I'm trying to calling 2 variables inside another procedure that should give me the min and max in a column like this:
create or replace procedure ClassEnrollmentReport
(p_CLASSNAME in class.classname%TYPE)
as
begin
dbms_output.put_line('Max gpa:');
StudentWithGivenGPA(MinMaxGPA.p_maxStudentGPA(p_CLASSNAME));
dbms_output.put_line('Min gpa:');
StudentWithGivenGPA(MinMaxGPA.p_minStudentGPA(p_CLASSNAME));
end ClassEnrollmentReport;
Which gives me an error message like this:
6/5 PL/SQL: Statement ignored
6/35 PLS-00225: subprogram or cursor 'MINMAXGPA' reference is out of scope
8/5 PL/SQL: Statement ignored
8/35 PLS-00225: subprogram or cursor 'MINMAXGPA' reference is out of scope
Here's how the minmaxgpa procedure look like:
create or replace procedure MinMaxGPA
(
p_CLASSNAME in class.classname%type,
p_maxStudentGPA OUT student.gpa%type,
p_minStudentGPA OUT student.gpa%type
)
as
maxStudentGPA student.gpa%type;
minStudentGPA student.gpa%type;
begin
select max(gpa) into maxStudentGPA
from student
where classno = (select classno from class where upper(classname) = upper(p_CLASSNAME));
select min(gpa) into minStudentGPA
from student
where classno = (select classno from class where upper(classname) = upper(p_CLASSNAME));
p_maxStudentGPA := maxStudentGPA;
p_minStudentGPA := minStudentGPA;
end MinMaxGPA;
I know how to do this with a function, but having no idea how can I get this with procedure. Can you help me with this?
With really simple sample tables (just to make the procedure compile):
SQL> create table class as select 'abc' classname, 100 clasno from dual;
Table created.
SQL> create table student as select 1 gpa, 100 classno from dual;
Table created.
Procedure code (I didn't change it):
SQL> create or replace procedure MinMaxGPA
2 (
3 p_CLASSNAME in class.classname%type,
4 p_maxStudentGPA OUT student.gpa%type,
5 p_minStudentGPA OUT student.gpa%type
6
7 )
8 as
9 maxStudentGPA student.gpa%type;
10 minStudentGPA student.gpa%type;
11 begin
12 select max(gpa) into maxStudentGPA
13 from student
14 where classno = (select classno from class where upper(classname) = upper(p_CLASSNAME));
15
16
17 select min(gpa) into minStudentGPA
18 from student
19 where classno = (select classno from class where upper(classname) = upper(p_CLASSNAME));
20
21 p_maxStudentGPA := maxStudentGPA;
22 p_minStudentGPA := minStudentGPA;
23 end MinMaxGPA;
24 /
Procedure created.
Your "new" ClassEnrollmentReport should then look like this: you have to follow the MinMaxGPA procedure's description - it accepts 3 parameters (one in, two out):
SQL> create or replace procedure ClassEnrollmentReport
2 (p_CLASSNAME in class.classname%TYPE)
3 as
4 v_mingpa number;
5 v_maxgpa number;
6 begin
7 minmaxgpa(p_classname, v_mingpa, v_maxgpa);
8 dbms_output.put_line('Max gpa: ' || v_maxgpa);
9 dbms_output.put_line('Min gpa: ' || v_mingpa);
10 end ClassEnrollmentReport;
11 /
Procedure created.
If we test it:
SQL> set serveroutput on
SQL> exec classenrollmentreport('abc');
Max gpa: 1
Min gpa: 1
PL/SQL procedure successfully completed.
SQL>

How do I loop through the value of a field in a table column?

I have a table naprav, where there are fields naprav_id and naprav_name, trying to write something like this:
For naprav_id in (select naprav_id from naprav)
Loop
select naprav_name from narrow where to.napravit=napravit
End loop;
I understand that this code is meaningless, but it is necessary to be able to go through the value of the fields in the loop. How can this be adequately implemented?
If I understood you correctly, that would be something like this:
SQL> declare
2 l_naprav_name naprav.naprav_name%type;
3 begin
4 for cur_r in (select naprav_id from naprav) loop
5 select naprav_name
6 into l_naprav_name
7 from naprav
8 where naprav_id = cur_r.naprav_id;
9
10 dbms_output.put_line(l_naprav_name);
11 end loop;
12 end;
13 /
CLARK
KING
MILLER
PL/SQL procedure successfully completed.
SQL>

How to pick a particular package based on a particular table column value in Oracle?

I have a situation here:
We need to run procedure_1 in a package when a particular column say column X has data in it and simultaneously run another procedure_2 in package if there is no data in that column X
Can anyone please advice on what can be done using Oracle ?
Something like this?
table DECIDE contains PARTICULAR_COLUMN
package has two simple procedures which do nothing; they just identify themselves
.
SQL> create table decide
2 (id number,
3 particular_column varchar2(1));
Table created.
SQL> insert into decide values (1, 'X');
1 row created.
SQL> insert into decide values (2, null);
1 row created.
SQL> create or replace package pkg_decide as
2 procedure p1;
3 procedure p2;
4 end;
5 /
Package created.
SQL> create or replace package body pkg_decide as
2 procedure p1 is
3 begin
4 dbms_output.put_line('-> running proc 1');
5 end;
6
7 procedure p2 is
8 begin
9 dbms_output.put_line('-> running proc 2');
10 end;
11 end;
12 /
Package body created.
SQL>
Testing: if the PARTICULAR_COLUMN isn't empty, P1 will run; otherwise, P2. That can be done with dynamic SQL, i.e. EXECUTE IMMEDIATE. As we're going to run a procedure, we have to form a full anonymous PL/SQL block (begin - procedure name - end).
P.S. As suggested by Matthew, a simple IF will do.
SQL> begin
2 for cur_r in (select particular_column,
3 case when particular_column is not null then 'pkg_decide.p1'
4 else 'pkg_decide.p2'
5 end prc_name
6 from decide
7 ) loop
8 dbms_output.put_line('particular column = ' || cur_r.particular_column ||
9 ', should run procedure ' || cur_r.prc_name);
10 execute immediate 'begin ' ||cur_r.prc_name ||'; end;';
11
12 -- Or, as suggested by Matthew, a simple IF will do
13 if cur_r.particular_column is not null then
14 pkg_decide.p1;
15 else
16 pkg_decide.p2;
17 end if;
18 end loop;
19 end;
20 /
particular column = X, should run procedure pkg_decide.p1
-> running proc 1
-> running proc 1
particular column = , should run procedure pkg_decide.p2
-> running proc 2
-> running proc 2
PL/SQL procedure successfully completed.
SQL>

Using cursor with where in condition

I am passing arguments `EBN,BGE' into a procedure , then I am passing this argument to a cursor.
create or replace procedure TEXT_MD (AS_IDS VARCHAR2)
is
CURSOR C_A (AS_ID VARCHAR2) IS
SELECT
name
FROM S_US
WHERE US_ID IN (AS_ID);
BEGIN
FOR A IN C_A (AS_IDS) LOOP
DBMS_OUTPUT.PUT_LINE('I got here: '||AS_IDS);
end loop;
END;
But while debuging the count of the cursor is still null
So my question , why the cursor not returning values with in condition
You are passing a string parameter, so it will be used as a string, not as a list of strings; so, your cursor will be something like
SELECT name
FROM S_US
WHERE US_ID IN ('EBN,BGE')
This will, of course, not do what you need.
You may need to change your procedure and the way to pass parameters; if you want to keep a string parameter , one way could be the following:
setup:
SQL> CREATE TABLE S_US
2 (
3 US_ID,
4 NAME
5 ) AS
6 SELECT 'EBN', 'EBN name' FROM DUAL
7 UNION ALL
8 SELECT 'BGE', 'BGE name' FROM DUAL;
Table created.
procedure:
SQL> CREATE OR REPLACE PROCEDURE TEXT_MD_2(AS_IDS VARCHAR2) IS
2 vSQL varchar2(1000);
3 c sys_refcursor;
4 vName varchar2(16);
5 BEGIN
6 vSQL := 'SELECT name
7 FROM S_US
8 WHERE US_ID IN (' || AS_IDS || ')';
9 open c for vSQL;
10 loop
11 fetch c into vName;
12 if c%NOTFOUND then
13 exit;
14 end if;
15 DBMS_OUTPUT.PUT_LINE(vName);
16 END LOOP;
17 END;
18 /
Procedure created.
You need to call it with a string already formatted to be a parameter list for IN:
SQL> EXEC TEXT_MD_2('''EBN'',''BGE''');
EBN name
BGE name
PL/SQL procedure successfully completed.
This is only an example of a possible way, and not the way I would do this.
Among the reasons to avoud this kind of approach, consider what Justin Cave says:
"that would be a security risk due to SQL injection and would have a potentially significant performance penalty due to constant hard parsing".
I believe you should better check how to pass a list of values to your procedure, rather then using a string to represent a list of strings.
Here is a possible way to do the same thing with a collection:
SQL> CREATE OR REPLACE TYPE tabVarchar2 AS TABLE OF VARCHAR2(16)
2 /
Type created.
SQL>
SQL> CREATE OR REPLACE PROCEDURE TEXT_MD_3(AS_IDS tabVarchar2) IS
2 vSQL VARCHAR2(1000);
3 c SYS_REFCURSOR;
4 vName VARCHAR2(16);
5 BEGIN
6 FOR i IN (SELECT name
7 FROM S_US INNER JOIN TABLE(AS_IDS) tab ON (tab.COLUMN_VALUE = US_ID))
8 LOOP
9 DBMS_OUTPUT.PUT_LINE(i.name);
10 END LOOP;
11 END;
12 /
Procedure created.
SQL>
SQL> DECLARE
2 vList tabVarchar2 := NEW tabVarchar2();
3 BEGIN
4 vList.EXTEND(2);
5 vList(1) := 'BGE';
6 vList(2) := 'EBN';
7 TEXT_MD_3(vList);
8 END;
9 /
BGE name
EBN name
PL/SQL procedure successfully completed.
SQL>
Again, you can define collections in different ways, within a stored procedure or not, indexed or not, and so on; this is only one of the possible ways, not necessarily the best, depending on your environment, needs.

Using cursor after a delete statement in a stored procedure [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Oracle Accessing updated records during the same transaction
I have an Oracle stored procedure somewhat like this (actual sqls are different)
CREATE OR REPLACE PROCEDURE mysp
IS
v_copied_row table%ROWTYPE ;
CURSOR p_copied_rows IS
select *
from table ;
BEGIN
delete from table
where <some condition>
OPEN p_copied_rows ;
LOOP
FETCH p_copied_rows into v_copied_rows ;
<do something with fetched row>
END LOOP
close p_copied_rows;
END;
Ideally, I am expecting that the deleted rows should not be part of the result set I am fetching from the cursor, but those are.
I am new to oracle, and want to understand if i am doing something wrong here?
P.S. I've to use cursor for some complex things, so replacing cursor with the SQL is not an option.
If your actual code matched the code you posted, the rows you you delete would not be returned by the cursor
If I create a table with 100 rows
SQL> ed
Wrote file afiedt.buf
1 create table foo
2 as
3 select level col1
4 from dual
5* connect by level <= 100
SQL> /
Table created.
and then create a PL/SQL block that replicates what you posted which deletes 98 of the rows, the cursor that is opened will return only 2 rows
SQL> select count(*) from foo;
COUNT(*)
----------
100
SQL> declare
2 cursor non_deleted_rows
3 is select *
4 from foo;
5 l_rec foo%rowtype;
6 begin
7 delete from foo
8 where col1 <= 98;
9
10 open non_deleted_rows;
11 loop
12 fetch non_deleted_rows into l_rec;
13 exit when non_deleted_rows%notfound;
14
15 dbms_output.put_line( l_rec.col1 );
16 end loop;
17 end;
18 /
99
100
PL/SQL procedure successfully completed.
Now, if you open the cursor before you issue the DELETE, the cursor will return the rows that were deleted. Perhaps in your actual code, the OPEN statement is before the DELETE.

Resources