Select object inside an object in PL/SQL - sql

I have the following code:
SET SERVEROUTPUT ON
CREATE OR REPLACE TYPE work_t AS OBJECT(
company VARCHAR2(50),
salary NUMBER(5)
);
/
CREATE OR REPLACE TYPE person_t AS OBJECT(
personnum NUMBER(5),
personname VARCHAR2(20),
personwork work_t
);
/
CREATE TABLE people OF person_t(
PRIMARY KEY (personnum)
);
INSERT INTO people VALUES(12, 'George', work_t('Google',75500));
If I want to print personname:
DECLARE
per1 person_t;
BEGIN
SELECT VALUE(e) INTO per1 FROM people e WHERE e.personnum = 12;
dbms_output.put_line(per1.personname);
END;
/
Now I want to print the company (and update it in different blocks) but I don't know how to do it.
Thanks.

Just add
dbms_output.put_line(per1.personwork.company);
in
DECLARE
per1 person_t;
BEGIN
SELECT VALUE(e) INTO per1 FROM people e WHERE e.personnum = 12;
dbms_output.put_line(per1.personname);
dbms_output.put_line(per1.personwork.company);
END;
/

Related

Oracle SQL Trigger Syntax

I am trying to create a trigger that checks if the faculty member to be added to the assigned table will is already on the qualified table for a specified class. Perhaps this is a tedious method. Nevertheless, I'd still like to know what I'm doing wrong. The following is my code with created the created tables and the trigger being the last part of the code:
CODE:
CREATE TABLE Faculty (
FId varchar(10),
FName varchar(20),
CONSTRAINT Faculty_ID_pk PRIMARY KEY(FId)
);
CREATE TABLE Course (
CId varchar(10),
CName varchar(20),
CONSTRAINT Course_ID_pk PRIMARY KEY(CId)
);
CREATE TABLE Qualify (
QDate DATE,
FId varchar(10),
CId varchar(10),
CONSTRAINT Qualifying_date CHECK(QDate >= TO_DATE('2020-08-24', 'YYYY-MM-DD')),
CONSTRAINT Qualify_FID_fk FOREIGN KEY(FId) REFERENCES Faculty(FId),
CONSTRAINT Qualify_CID_fk FOREIGN KEY(CId) REFERENCES Course(CId)
);
CREATE TABLE Assign (
ADate DATE,
FId varchar(10),
CId varchar(10),
CONSTRAINT Qualifying_check CHECK(ADate > TO_DATE('2020-08-24', 'YYYY-MM-DD')),
CONSTRAINT Assign_FID_fk FOREIGN KEY(FId) REFERENCES Faculty(FId),
CONSTRAINT Assign_CID_fk FOREIGN KEY(CId) REFERENCES Course(CId)
);
CREATE OR REPLACE TRIGGER Check_If_Qualified
BEFORE INSERT ON Assign
FOR EACH ROW
DECLARE
v_facNum number;
BEGIN
SELECT f.FId
into v_facNum
from Faculty f
where f.facnum = :new.fid;
END;
However, I keep receiving an error saying:
Error at line 7: PLS-00225: subprogram or cursor 'F' reference is out of scope
v_facNum number;
BEGIN
SELECT f.FId
into v_facNum
from Faculty f
Does anyone know what could be wrong?
There are lots of issues in your code. You can check the count of records into FACULTY table and use that count for whatever logic you want.
CREATE OR REPLACE TRIGGER CHECK_IF_QUALIFIED
BEFORE INSERT ON ASSIGN
FOR EACH ROW
DECLARE
CNT NUMBER;
BEGIN
SELECT COUNT(1)
INTO CNT
FROM FACULTY
WHERE FACNUM = :NEW.FID;
END;
/
That would be something like this (sample tables are really just a sample; they are here to make the trigger compile):
SQL> create table assign (fid number);
Table created.
SQL> create table faculty (facnum number, fid number);
Table created.
SQL> CREATE OR REPLACE TRIGGER Check_If_Qualified
2 BEFORE INSERT ON Assign
3 FOR EACH ROW
4 DECLARE
5 v_facNum number;
6 BEGIN
7 SELECT f.FId
8 into v_facNum
9 from Faculty f
10 where f.facnum = :new.fid;
11
12 -- now do something with v_facNum
13 END;
14 /
Trigger created.
SQL>

PL/SQL Error: ORA-00984 Column not allowed here

I am writing a cursor for loop to retrieve a portion of data from table A and insert it into table B. When I run my code, I receive this error:
Here is the code I'm working with:
CREATE TABLE New_Movie (
ID INTEGER NOT NULL,
title VARCHAR2(100),
yr NUMBER(4,0),
score NUMBER,
votes INTEGER,
director VARCHAR2(100),
CONSTRAINT New_Movie_PK PRIMARY KEY (id));
DECLARE
counter INTEGER;
CURSOR c_movie IS
SELECT ID, title, yr, score, votes, director
from movie
where votes >= 50000;
BEGIN
counter := 0;
for n_movie IN c_movie
LOOP
counter := counter+1;
dbms_output.put_line(counter|| 'rows have been inserted');
INSERT INTO New_Movie VALUES(id, title, yr, score, votes, director);
END LOOP;
EXECUTE IMMEDIATE 'COMMIT';
END;
can you try this one
INSERT INTO New_Movie
VALUES(n_movie .id,
n_movie.title,
n_movie.yr,
n_movie.score,
n_movie.votes,
n_movie.director);
In insert statement, you should write n_movie at the beginning of each column.
CREATE TABLE New_Movie (
ID INTEGER NOT NULL,
title VARCHAR2(100),
yr NUMBER(4,0),
score NUMBER,
votes INTEGER,
director VARCHAR2(100),
CONSTRAINT New_Movie_PK PRIMARY KEY (id));
DECLARE
counter INTEGER;
CURSOR c_movie IS
SELECT ID, title, yr, score, votes, director
from movie
where votes >= 50000;
BEGIN
counter := 0;
for n_movie IN c_movie
LOOP
counter := counter+1;
dbms_output.put_line(counter|| 'rows have been inserted');
INSERT INTO New_Movie VALUES(n_movie.id, n_movie.title, n_movie.yr, n_movie.score, n_movie.votes, n_movie.director);
END LOOP;
EXECUTE IMMEDIATE 'COMMIT';
END;

Error in Initializing oracle collection

I have following self contained code which gives following error. I don't seem to find where do I have to initialize the collection.
create or replace type address_type is object
(
address_line varchar2(100),
city varchar2(100),
state varchar2(100)
)
/
create or replace type emp_rec_type is object
(
emp_name varchar2(100),
addr_rec address_type
)
/
create or replace type emp_arr is table of emp_rec_type
/
create table employees
(
emp_name varchar2(100),
addr_rec address_type
)
/
insert into employees values ( 'dave', address_type ( '30 br','br','nj'));
commit;
-- Create a function to return an array
create or replace function get_emp_rec ( p_name in varchar2 )
return
emp_arr
is
i integer;
l_arr emp_arr := emp_arr();
begin
i := 1;
l_arr.extend;
l_arr(l_arr.last).emp_name := 'a';
l_arr(l_arr.last).addr_rec := address_type ( 'a','b','c');
return l_arr;
end;
/
select emp_name from table ( get_emp_rec( 'dave' ))
* ERROR at line 1: ORA-06530: Reference to uninitialized composite ORA-06512: at "DBADMIN.GET_EMP_REC", line
22
You have to initialize emp_rec_type in the collection.
These two line
l_arr(l_arr.last).emp_name := 'a';
l_arr(l_arr.last).addr_rec := address_type ( 'a','b','c');
replace with this linie
l_arr(l_arr.last) := emp_rec_type('a', address_type ( 'a','b','c'));

Getting difference between two dates from 2 REF'd columns

I'm new to SQL and I'm trying to get the date between 2 values between two REF'd column values.
I currently have the tables set up like below:
CREATE OR REPLACE TYPE Person_Type AS OBJECT
(PersonId NUMBER,
DateBorn DATE)
CREATE OR REPLACE TYPE Movie_Type AS OBJECT
(MovieId NUMBER,
ReleaseDate DATE)
CREATE OR REPLACE TYPE Role_Type AS OBJECT
(PersonId REF Person_Type,
MovieId REF Movie_Type,
Name VARCHAR2(40),
MAP MEMBER FUNCTION Actor_Age RETURN NUMBER)
The data is inserted like this:
INSERT INTO Person_Table
VALUES (10000, '11-NOV-1974')
INSERT INTO Movie_Table
VALUES(1000000, '19-DEC-1997')
INSERT INTO Role_Table
VALUES((SELECT REF(a) FROM Person_Table a WHERE a.PersonId = 10000),
(SELECT REF(b) FROM Movie_Table b WHERE b.MovieId = 1000000),
'Some Person')
I'm trying to get the method Actor_Age to return the difference between the day someone is born and the date the movie got released. I've tried the below but it won't compile..
CREATE OR REPLACE TYPE BODY Role_Type
AS
MAP MEMBER FUNCTION Actor_Age
RETURN NUMBER
IS
BEGIN
RETURN (MONTHS_BETWEEN((SELECT g.PersonId.DateBorn FROM Role_Table g),
(SELECT f.MovieId.Releasedate FROM Role_Table f)/12));
END;
END;
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE OR REPLACE TYPE Person_Type AS OBJECT
(PersonId NUMBER,
DateBorn DATE)
/
CREATE OR REPLACE TYPE Movie_Type AS OBJECT
(MovieId NUMBER,
ReleaseDate DATE)
/
CREATE OR REPLACE TYPE Role_Type AS OBJECT
(PersonId REF Person_Type,
MovieId REF Movie_Type,
Name VARCHAR2(40),
MAP MEMBER FUNCTION Actor_Age RETURN NUMBER)
/
CREATE OR REPLACE TYPE BODY Role_Type
AS
MAP MEMBER FUNCTION Actor_Age
RETURN NUMBER
IS
p_age NUMBER;
BEGIN
SELECT MONTHS_BETWEEN(
DEREF( MovieID ).ReleaseDate,
DEREF( PersonID ).DateBorn
) / 12
INTO p_age
FROM DUAL;
RETURN p_age;
END;
END;
/
CREATE TABLE Person_Table OF Person_Type
/
CREATE TABLE Movie_Table OF Movie_Type
/
CREATE TABLE Role_Table OF Role_Type
/
INSERT INTO Person_Table VALUES ( 10000, DATE '1970-01-01' )
/
INSERT INTO Movie_Table VALUES ( 1000000, DATE '2000-01-01' )
/
INSERT INTO Role_Table VALUES(
(SELECT REF(a) FROM Person_Table a WHERE a.PersonId = 10000),
(SELECT REF(b) FROM Movie_Table b WHERE b.MovieId = 1000000),
'Some Person'
)
/
Query 1:
SELECT Name,
r.Actor_Age()
FROM Role_table r
Results:
| NAME | R.ACTOR_AGE() |
|-------------|---------------|
| Some Person | 30 |
In pl sql you have to use construction select into
CREATE OR REPLACE TYPE BODY Role_Type
AS
MAP MEMBER FUNCTION Actor_Age
RETURN NUMBER
IS
v_date_born date ;
v_realse_date date ;
BEGIN
SELECT deref(self.PersonId).DateBorn into v_date_born FROM dual;
SELECT deref(self.MovieId).Releasedate into v_realse_date FROM dual;
RETURN (MONTHS_BETWEEN(v_date_born,v_realse_date)/12);
END;
END;

Procedure created with compilation errors - but can't find error

I have a procedure but I can't find where the error is:
CREATE OR REPLACE PROCEDURE ADD_GRADE (
STUDEN_ID IN VARCHAR2(6),
SEC_ID IN NUMBER(6),
NEW_GRADE IN CHAR (1)
)
AS
BEGIN
UPDATE ENROLLMENT
SET grade = NEW_GRADE
WHERE s_id = STUDEN_ID AND c_sec_id = SEC_ID;
END;
/
Run this query ..
select * from user_errors where name ='ADD_GRADE'
and youll have your error
All respect goes to #MarkLeiber who spotted the error...
Try this instead:
CREATE OR REPLACE PROCEDURE ADD_GRADE (
STUDEN_ID IN VARCHAR2,
SEC_ID IN NUMBER,
NEW_GRADE IN CHAR
)
AS
BEGIN
UPDATE ENROLLMENT
SET grade = NEW_GRADE WHERE s_id = STUDEN_ID AND c_sec_id = SEC_ID;
END;
/