PL/SQL: Member of method with "where" - plsql

How could I do this:
Select values from three different columns into nested table or some other kind of collection...
DECLARE
TYPE blockers_set IS TABLE OF (
employee_ID NUMBER(8),
BLOCKING_GROUP NUMBER(4),
BLOCKING_TYPE NUMBER2(2));
select employee_ID, BLOCKING_GROUP, BLOCKING_TYPE
bulk collect into blockers
from blockers;
...and refer to columns:
if employee_ID not member of blockers where blocking_group = 1
and blocking_type = 2
then <<business logic>>
There can be more than one row for one employee_ID in blockers-collection.
This is has to be done with pl/sql.

You can do it as follows:
CREATE TABLE blockers(
employee_id NUMBER(8),
blocking_group NUMBER(4),
blocking_type number(2));
===============================
select * from blockers;
===============================
Create or replace type OBJ_BLOCKERS as OBJECT(
employee_id NUMBER(8),
blocking_group NUMBER(4),
blocking_type number(2)
);
=================================================
Create or replace type varble is table of OBJ_BLOCKERS;
===================================================
DECLARE
--Creating one element for comparision. In your case you need to populate your employee_id to be compared here.
tmp OBJ_BLOCKERS:=OBJ_BLOCKERS(263427,1,2);
var varble;
myid INT;
begin
--This how you Select values from three different columns into nested table(Object)
Select OBJ_BLOCKERS(employee_id,
blocking_group,
blocking_type)
Bulk Collect into var
from blockers;
-- Displaying Employee_Id from the collection
For i in 1..var.count
loop
dbms_output.put_line(var(i).employee_id);
end loop;
--
SELECT 1
INTO myid
FROM TABLE(var) q
where OBJ_BLOCKERS(q.employee_id,q.blocking_group,q.blocking_type) = tmp --Here you are comparing the employee_id which should be a member of collection
AND q.blocking_group = 1;
IF (myid = 1) THEN
dbms_output.put_line('OK, exists.');
END IF;
Exception
When No_DATa_found then
dbms_output.put_line('No Data Found');
End;
Execution:
SQL> /
263427
534366
454562
OK, exists.
PL/SQL procedure successfully completed.
Note that:
if employee_ID not member of blockers where blocking_group = 1 and
blocking_type = 2
This is not possible using a Member Funtion. You need to declare a MAP method, which is rather clunky and would get rather annoying if the object has a lot of attributes(just like your case).

Related

I want to use out parameter ,but I am not getting the proper syntax of doing so,:ORA-00900: invalid SQL statement

Problem definition: Create a procedure which will display the employees in descending order of employee name of
computer department.
CREATE OR REPLACE PROCEDURE pr_disp (name OUT VARCHAR2,
age OUT NUMBER,
dep OUT VARCHAR,
salary OUT NUMBER)
AS
CURSOR c
IS
SELECT name,
age,
department,
salary
FROM enployee2
WHERE department = 'Computer'
ORDER BY name DESC;
this_name enployee2.name%TYPE;
this_age enployee2.age%TYPE;
this_dep enployee2.department%TYPE;
this_sal enployee2.salary%TYPE;
BEGIN
OPEN c1;
LOOP
FETCH c1
INTO this_name,
this_age,
this_dep,
this_sal;
DBMS_OUTPUT.put_line (
this_name || ' ' || this_age || ' ' || this_dep || '
' || this_sal);
EXIT WHEN c1%NOTFOUND;
END LOOP;
CLOSE c1;
END;
/
Maybe there is a problem in my execution part...
execution part:
variable nm varchar2(50);
variable age number
variable dep varchar2(50);
variable sal number;
execute pr_disp(nm,age,dep,sal);
.The error comes when I execute the code is :ORA-00900: invalid SQL statement
Your code has several errors. Please see below to find out what and where:
Table Creation:
create table enployee2( name VARCHAR2(100),
age NUMBER,
department VARCHAR2(100),
salary NUMBER
);
INSERT INTO enployee2 VALUES ('AAA',32,'Computer',2344);
INSERT INTO enployee2 VALUES ('BBB',42,'Computer',4400);
insert into enployee2 values ('CCC',21,'Computer',2454);
Procedure:
Create OR REPLACE PROCEDURE pr_disp(
name OUT VARCHAR2,
age OUT NUMBER,
dep OUT VARCHAR,
salary OUT NUMBER)
AS
CURSOR c --<-- Your cursor name is `C` but you used it as `C1` below while opening and closing
IS
SELECT name,
age,
department,
salary
FROM enployee2
WHERE department ='Computer'
ORDER BY name DESC;
this_name enployee2.name%type;
this_age enployee2.age%type;
this_dep enployee2.department%type;
this_sal enployee2.salary%TYPE;
BEGIN
OPEN c; --<--Opening `C1` while your cursor name is `C`
LOOP
FETCH c INTO this_name,this_age,this_dep,this_sal;
dbms_output.put_line(this_name||' '||this_age||' '||this_dep||' '||this_sal);
EXIT WHEN c%NOTFOUND; --<--Exiting `C1` while your cursor name is `C`
END LOOP;
CLOSE c; --<--Closing `C1` while your cursor name is `C`
END;
/
Execution:
DECLARE
nm VARCHAR2(50);
age NUMBER;
dep VARCHAR2(50);
sal NUMBER;
BEGIN
pr_disp(nm,age,dep,sal);
END;
You have to write a PL/SQL-Block like this:
DECLARE
nm VARCHAR2 (50);
age NUMBER; -- here you were missing a semi-colon
dep VARCHAR2 (50);
sal NUMBER;
BEGIN
pr_disp (nm,
age,
dep,
sal);
END;
I would assume your stored procedure is invalid because of compilation errors. Try compiling again and check the messages.
You can also check the status with:
select status from user_objects where object_name='PR_DISP';
If it's INVALID you should be able to obtain error messages also via:
select * from user_errors where name = 'PR_DISP';
Maybe your table is named employee2 (not enployee2)?
Btw: What are the out parameters for? You never use them.

How to get value from nested table in pl sql table

I have created nested table as follow:
CREATE OR REPLACE TYPE EMP_NO_NAME
AS OBJECT
(
EMPNO NUMBER(4),
ENAME VARCHAR2(20),
JOB VARCHAR2(20),
MGR NUMBER(5),
HIREDATE DATE,
SAL NUMBER(7,2)
);
CREATE OR REPLACE TYPE EMP_TABLE IS TABLE OF EMP_NO_NAME;
-----------------------
CREATE TABLE NESTED_EMP
(
DEPTNO NUMBER(2) ,
EMPLOYEE EMP_TABLE
)
NESTED TABLE EMPLOYEE STORE AS NESTED_EMPLOYEE;
INSERT INTO NESTED_EMP (DEPTNO,EMPLOYEE)
VALUES (10,EMP_TABLE(EMP_NO_NAME(7839,'KING','PRESIDENT',NULL,'17-NOV-81',5000),
EMP_NO_NAME(7782,'CLARK','MANAGER',7839,'09-JUN-81',2450),
EMP_NO_NAME(7934,'MILLER','CLERK',7782,'23-JAN-82',1300)
)
);
INSERT INTO NESTED_EMP (DEPTNO,EMPLOYEE)
VALUES (20,EMP_TABLE(EMP_NO_NAME(7566,'JONES','MANAGER',7839,'02-APR-81',2975),
EMP_NO_NAME(7902,'FORD','ANALYST',7566,'03-DEC-81',3000),
EMP_NO_NAME(7369,'SMITH','CLERK',7902,'17-DEC-80',800),
EMP_NO_NAME(7788,'SCOTT','ANALYST',7566,'09-DEC-82',3000),
EMP_NO_NAME(7876,'ADAMS','CLERK',7788,'12-JAN-83',1100)
)
);
INSERT INTO NESTED_EMP (DEPTNO,EMPLOYEE)
VALUES (20,EMP_TABLE(EMP_NO_NAME(7698,'BLAKE','MANAGER',7839,'01-MAY-81',2850),
EMP_NO_NAME(7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250),
EMP_NO_NAME(7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600),
EMP_NO_NAME(7844,'TURNER','SALESMAN',7698,'08-SEP-81',1500),
EMP_NO_NAME(7900,'JAMES','CLERK',7698,'03-DEC-81',950),
EMP_NO_NAME(7521,'WARD','SALESMAN',7698,'22-FEB-81',1250)
)
);
Now I getting the value of nested table in plsql:
DECLARE
CURSOR EMPLOYEE IS
select p.* from NESTED_EMP p1 ,table(p1.employee) p;
V_EMP EMP_TABLE;
BEGIN
FOR V_EMP IN EMPLOYEE
LOOP
EXIT WHEN EMPLOYEE%NOTFOUND;
END LOOP;
FOR MYINDEX IN V_EMP.FIRST..V_EMP.LAST
LOOP
DBMS_OUTPUT.PUT_LINE(V_EMP(MYINDEX).ENAME);
END LOOP;
END;
/
END;
Error report:
ORA-06531: Reference to uninitialized collection ORA-06512: at line 10
06531. 00000 - "Reference to uninitialized collection"
*Cause: An element or member function of a nested table or varray
was referenced (where an initialized collection is needed)
without the collection having been initialized.
*Action: Initialize the collection with an appropriate constructor
or whole-object assignment.
How to get nested table value in plsql table ?
The problem with your code is that V_EMP is not actually of type EMP_TABLE. Rather, it's an EMPLOYEE.ROWTYPE. When you initialize a cursor for loop, the variable is automatically made an appropriate ROWTYPE, overriding any previous declarations.
The good news is that, since you've already referenced the nested table in the query, you don't need to do so in the loop (it's already been exploded). Your PL/SQL can be vastly simplified:
DECLARE
CURSOR employee IS
SELECT p.*
FROM nested_emp p1 CROSS JOIN TABLE (p1.employee) p;
BEGIN
FOR v_emp IN employee LOOP
DBMS_OUTPUT.put_line (v_emp.ename);
END LOOP;
END;
/
You'll notice the EXIT WHEN was removed as well. A cursor for loop terminates automatically after the last record.
An alternative would be to not explode the nested table in the query. Then you would need two loops:
DECLARE
CURSOR employee IS
SELECT p.*
FROM nested_emp p;
BEGIN
FOR v_emp IN employee LOOP
for i in v_emp.employee.first..v_emp.employee.last loop
DBMS_OUTPUT.put_line (v_emp.employee(i).ename);
end loop;
END LOOP;
END;
/

PL SQL: How to populate a cursor in loop

I have a scenario to implement where in we will have an SP with two parameters
1) In parameter of array of Varchar2
2) Cursor -- Out parameter
We have populate the cursor only for each Value passed in array and this opened/populated cursor will be used by Java. But what i have found till now is, if we have to process an array then it should have to be done using loop.
For ex:
Open Cursor_Name
For
For index In Arrar_Parameter.FIRST .. Arrar_Parameter.LAST
LOOP
SELECT * FROM EMP WHERE EmpId = Arrar_Parameter[i] -------> This needs to be looped and not sure if this will work
END LOOP
Can we have some thing like this
Open Cursor_Name
For
SELECT * FROM EMP WHERE EmpId IN (Arrar_Parameter values) ------> To fetch/put all the array values at once without loop.
Kindly suggest hot to populate cursor in this scenario
Assuming your array parameter is a schema-level varray or nested table, you can use a table collection expression:
The table_collection_expression lets you inform Oracle that the value of collection_expression should be treated as a table for purposes of query and DML operations. The collection_expression can be a subquery, a column, a function, or a collection constructor. Regardless of its form, it must return a collection value—that is, a value whose type is nested table or varray. This process of extracting the elements of a collection is called collection unnesting.
This uses a built-in varray type but you can substitute your own:
create procedure procedure_name (
array_parameter sys.odcivarchar2list, cursor_name out sys_refcursor
) as
begin
open cursor_name for
select e.*
from table (array_parameter) a
join emp e on e.empid = a.column_value;
end;
/
You can also use in if you prefer:
create procedure procedure_name (
array_parameter sys.odcivarchar2list, cursor_name out sys_refcursor
) as
begin
open cursor_name for
select *
from emp
where empid in (select column_value from table (array_parameter));
end;
/
If it is a nested table you can also use the member of syntax:
create type my_varchar2_table as table of varchar2(30);
/
create procedure procedure_name (
array_parameter my_varchar2_table, cursor_name out sys_refcursor
) as
begin
open cursor_name for
select *
from emp
where empid member of array_parameter;
end;
/

PL/SQL Trigger gets a mutating table error

My trigger wants to check if a 'new' manager supervises no more than 5 employees.
Manager supervising only 5 people are in BLOCKED_MANAGER table(ssn,numberofemployees).
Finally, every update is recorded in SUPERLOG table(date,user,old_manager,new_manager).
I get no compiling error about the trigger, but when I update a superssn I get this error:
SQL> update employee set superssn='666666607' where ssn='111111100';
update employee set superssn='666666607' where ssn='111111100'
*
ERROR at line 1:
ORA-04091: Table FRANK.EMPLOYEE is mutating, the trigger/function
can't read it
ORA-06512: a "FRANK.TLOG", line 20
ORA-04088: error during execution of trigger 'FRANK.TLOG'
How can I solve this trigger? Thank you
create or replace trigger tlog
before update of superssn on employee
for each row
declare
t1 exception;
n number:=0;
cont number:=0;
empl varchar2(16);
cursor cur is (select ssn from blocked_manager where ssn is not null);
begin
open cur;
loop
fetch cur into empl;
exit when cur%notfound;
if(:new.superssn = empl) then
n:=1;
end if;
end loop;
close cur;
if n=1 then
raise t1;
end if;
select count(*) into cont from employee group by superssn having superssn=:new.superssn;
if(cont=4) then
insert into blocked_manager values(:new.superssn,5);
end if;
insert into superlog values(sysdate,user,:old.superssn, :new.superssn );
exception
when t1 then
raise_application_error(-20003,'Manager '||:new.superssn||' has already 5 employees');
end;
Probably the quickest way around this is to use a carefully constructed statement trigger instead of a row trigger. Row triggers have the phrase FOR EACH ROW in them, are invoked for each row which is modified (based on the BEFORE/AFTER INSERT, BEFORE/AFTER UPDATE, and BEFORE/AFTER DELETE constraints on the trigger), can see the appropriate :NEW and :OLD values, and are subject to the "can't look at the table on which the trigger is defined" rule. Statement triggers are invoked at the appropriate time for each statement which is executed, can't see row values, but aren't subject to the limits on looking at the particular table on which they're defined. So for the portions of your logic which don't need to work with :NEW or :OLD values a trigger such as this might prove useful:
CREATE OR REPLACE TRIGGER EMPLOYEE_S_BU
BEFORE UPDATE ON EMPLOYEE
-- Note: no BEFORE EACH ROW phrase, so this is a statement trigger
BEGIN
-- The following FOR loop should insert rows into BLOCKED_MANAGER for all
-- supervisors which have four or more employees under them and who are not
-- already in BLOCKED_MANAGER.
FOR aRow IN (SELECT e.SUPERSSN, COUNT(e.SUPERSSN) AS EMP_COUNT
FROM EMPLOYEE e
LEFT OUTER JOIN BLOCKED_MANAGER b
ON b.SSN = e.SUPERSSN
WHERE b.SSN IS NULL
GROUP BY e.SUPERSSN
HAVING COUNT(e.SUPERSSN) >= 4)
LOOP
INSERT INTO BLOCKED_MANAGER
(SSN, EMPLOYEE_COUNT)
VALUES
(aRow.SUPERSSN, aRow.EMP_COUNT);
END LOOP;
-- Remove rows from BLOCKED_MANAGER for managers who supervise fewer
-- than four employees.
FOR aRow IN (SELECT e.SUPERSSN, COUNT(e.SUPERSSN) AS EMP_COUNT
FROM EMPLOYEE e
INNER JOIN BLOCKED_MANAGER b
ON b.SSN = e.SUPERSSN
GROUP BY e.SUPERSSN
HAVING COUNT(e.SUPERSSN) <= 3)
LOOP
DELETE FROM BLOCKED_MANAGER
WHERE SSN = aRow.SUPERSSN;
END LOOP;
-- Finally, if any supervisor has five or more employees under them,
-- raise an exception. Note that we go directly to EMPLOYEE to determine
-- the number of employees supervised.
FOR aRow IN (SELECT SUPERSSN, COUNT(*) AS EMP_COUNT
FROM EMPLOYEE
GROUP BY SUPERSSN
HAVING COUNT(*) >= 5)
LOOP
-- If we get here we've found a supervisor with 5 (or more) employees.
-- Raise an exception
RAISE_APPLICATION_ERROR(-20000, 'Found supervisor ' || aRow.SUPERSSN ||
' supervising ' || aRow.EMP_COUNT ||
' employees');
END LOOP;
END EMPLOYEE_S_BU;
Note that if you get rid of the BLOCKED_MANAGER table (which this trigger still maintains, although I don't know if it's truly necessary) the logic gets cut down considerably.
You'll still need a row trigger to handle the logging, but as that's just a matter of cutting down your existing trigger I'll leave that to you. :-)
Share and enjoy.
As you have discovered, you cannot select from the same table that a row-level trigger is defined against; it causes a table mutating exception.
In order to properly create this validation using a trigger a procedure should be created to obtain user-specified locks so the validation can be correctly serialized in a multi-user environment.
PROCEDURE request_lock
(p_lockname IN VARCHAR2
,p_lockmode IN INTEGER DEFAULT dbms_lock.x_mode
,p_timeout IN INTEGER DEFAULT 60
,p_release_on_commit IN BOOLEAN DEFAULT TRUE
,p_expiration_secs IN INTEGER DEFAULT 600)
IS
-- dbms_lock.allocate_unique issues implicit commit, so place in its own
-- transaction so it does not affect the caller
PRAGMA AUTONOMOUS_TRANSACTION;
l_lockhandle VARCHAR2(128);
l_return NUMBER;
BEGIN
dbms_lock.allocate_unique
(lockname => p_lockname
,lockhandle => p_lockhandle
,expiration_secs => p_expiration_secs);
l_return := dbms_lock.request
(lockhandle => l_lockhandle
,lockmode => p_lockmode
,timeout => p_timeout
,release_on_commit => p_release_on_commit);
IF (l_return not in (0,4)) THEN
raise_application_error(-20001, 'dbms_lock.request Return Value ' || l_return);
END IF;
-- Must COMMIT an autonomous transaction
COMMIT;
END request_lock;
This procedure can then be used in a compound trigger (assuming at least Oracle 11, this will need to be split into individual triggers in earlier versions)
CREATE OR REPLACE TRIGGER too_many_employees
FOR INSERT OR UPDATE ON employee
COMPOUND TRIGGER
-- Table to hold identifiers of inserted/updated employee supervisors
g_superssns sys.odcivarchar2list;
BEFORE STATEMENT
IS
BEGIN
-- Reset the internal employee supervisor table
g_superssns := sys.odcivarchar2list();
END BEFORE STATEMENT;
AFTER EACH ROW
IS
BEGIN
-- Store the inserted/updated supervisors of employees
IF ( ( INSERTING
AND :new.superssn IS NOT NULL)
OR ( UPDATING
AND ( :new.superssn <> :old.superssn
OR :new.superssn IS NOT NULL AND :old.superssn IS NULL) ) )
THEN
g_superssns.EXTEND;
g_superssns(g_superssns.LAST) := :new.superssn;
END IF;
END AFTER EACH ROW;
AFTER STATEMENT
IS
CURSOR csr_supervisors
IS
SELECT DISTINCT
sup.column_value superssn
FROM TABLE(g_superssns) sup
ORDER BY sup.column_value;
CURSOR csr_constraint_violations
(p_superssn employee.superssn%TYPE)
IS
SELECT count(*) employees
FROM employees
WHERE pch.superssn = p_superssn
HAVING count(*) > 5;
r_constraint_violation csr_constraint_violations%ROWTYPE;
BEGIN
-- Check if for any inserted/updated employee there exists more than
-- 5 employees for the same supervisor. Serialise the constraint for each
-- superssn so concurrent transactions do not affect each other
FOR r_supervisor IN csr_supervisors LOOP
request_lock('TOO_MANY_EMPLOYEES_' || r_supervisor.superssn);
OPEN csr_constraint_violations(r_supervisor.superssn);
FETCH csr_constraint_violations INTO r_constraint_violation;
IF csr_constraint_violations%FOUND THEN
CLOSE csr_constraint_violations;
raise_application_error(-20001, 'Supervisor ' || r_supervisor.superssn || ' now has ' || r_constraint_violation.employees || ' employees');
ELSE
CLOSE csr_constraint_violations;
END IF;
END LOOP;
END AFTER STATEMENT;
END;
You do not need the blocked_manager table to manage this constraint. This information can be derived from the employee table.
Or in versions earlier than Oracle 11i:
CREATE OR REPLACE PACKAGE employees_trg
AS
-- Table to hold identifiers of inserted/updated employee supervisors
g_superssns sys.odcivarchar2list;
END employees_trg;
CREATE OR REPLACE TRIGGER employee_biu
BEFORE INSERT OR UPDATE ON employee
IS
BEGIN
-- Reset the internal employee supervisor table
employees_trg.g_superssns := sys.odcivarchar2list();
END;
CREATE OR REPLACE TRIGGER employee_aiur
AFTER INSERT OR UPDATE ON employee
FOR EACH ROW
IS
BEGIN
-- Store the inserted/updated supervisors of employees
IF ( ( INSERTING
AND :new.superssn IS NOT NULL)
OR ( UPDATING
AND ( :new.superssn <> :old.superssn
OR :new.superssn IS NOT NULL AND :old.superssn IS NULL) ) )
THEN
employees_trg.g_superssns.EXTEND;
employees_trg.g_superssns(employees_trg.g_superssns.LAST) := :new.superssn;
END IF;
END;
CREATE OR REPLACE TRIGGER employee_aiu
AFTER INSERT OR UPDATE ON employee
IS
DECLARE
CURSOR csr_supervisors
IS
SELECT DISTINCT
sup.column_value superssn
FROM TABLE(employees_trg.g_superssns) sup
ORDER BY sup.column_value;
CURSOR csr_constraint_violations
(p_superssn employee.superssn%TYPE)
IS
SELECT count(*) employees
FROM employees
WHERE pch.superssn = p_superssn
HAVING count(*) > 5;
r_constraint_violation csr_constraint_violations%ROWTYPE;
BEGIN
-- Check if for any inserted/updated employee there exists more than
-- 5 employees for the same supervisor. Serialise the constraint for each
-- superssn so concurrent transactions do not affect each other
FOR r_supervisor IN csr_supervisors LOOP
request_lock('TOO_MANY_EMPLOYEES_' || r_supervisor.superssn);
OPEN csr_constraint_violations(r_supervisor.superssn);
FETCH csr_constraint_violations INTO r_constraint_violation;
IF csr_constraint_violations%FOUND THEN
CLOSE csr_constraint_violations;
raise_application_error(-20001, 'Supervisor ' || r_supervisor.superssn || ' now has ' || r_constraint_violation.employees || ' employees');
ELSE
CLOSE csr_constraint_violations;
END IF;
END LOOP;
END;

How to use variable of declare at the where of select?

How to use variable of declare at the where of select ?
CREATE TABLE student (
id smallint PRIMARY KEY,
first_name VARCHAR(80) NOT NULL,
last_name VARCHAR(80) NOT NULL);
insert into student VALUES(10,'AA','A01');
insert into student VALUES(30,'BB','B01');
---MSSQL OK
declare #v_first varchar(10);
set #v_first='AA';
select * from student where first_name=#v_first;
---ORACLE --ERROR
declare v_first varchar2(10);
BEGIN
v_first :='AA';
select * from student where first_name= v_first;
END;
---=> MESSAGE
ORA-06550: line 4 , column 3 :
PLS-00428: 在此 SELECT 敘述句中預期會出現一個 INTO 子句
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The example you gave for MSSQL is a different table, but assuming DEPT_ID from USER_LIST is a NUMBER too... SQL will automatically convert the string to compare...
You need to cast the id to a number. Is there a reason you are declaring a varchar variable right before comparing it against a number?
declare v_id varchar2(2);
BEGIN
v_id :='30';
select * from student where id= TO_NUMBER(v_id);
END;
or change the declare and the assignment...
declare v_id NUMBER;
BEGIN
v_id :=30;
select * from student where id= v_id;
END;
basically, what the link I added in the comments below said.. from user tvm.. "You cannot use SELECT without INTO clause in PL/SQL. The output of the SELECT must be stored somewhere. Eg. table or variable or perhaps a record. See example below how to store result of the SELECT statement into record."
DECLARE
v_id number;
v_result Student%ROWTYPE;
BEGIN
v_id := 30;
SELECT * INTO v_result
FROM Student
WHERE id = v_id;
END;
Then you need to do something with v_result... other option shown is to call straight SQL - all depends on how you call and consume the data..

Resources