Oracle - Query about data in a collection of reference - sql

I am new to Oracle, I had a question which I can not sort out by myself.
I am building a movie database.
There is my design:
In the movie table, there are many actors, but movie table and actor table should be independent. So I am using a collection of REF link of actors in the movie table.
There is brief code:
CREATE OR REPLACE TYPE actor_type AS OBJECT (
name VARCHAR2(50) );
/
CREATE OR REPLACE TYPE actor_type_array IS
VARRAY ( 100 ) OF REF actor_type;
/
CREATE OR REPLACE TYPE movie_type AS OBJECT (
actor actor_type_array
);
/
CREATE TABLE movie OF movie_type;
/
INSERT INTO movie(actor)
VALUES(
actor_type_array(
(SELECT REF(a) FROM actor a WHERE a.name = 'A'),
(SELECT REF(a) FROM actor a WHERE a.name = 'B')
));
When I do my query, I wanted to get the list of actor name of a given movie,
I did in this way:
select a.name from movie m, table(m.actor)a;
but it said error-a.name is an invalid identifier, but when i replaced it with
select * from movie m, table(m.actor)a;
I got two reference link to actors. But the specific data inside the actor table didn't reveal.
I have googled it for several days, but found nothing. Can anyone help me with it? Thank you.

Related

INSERTING VALUES INTO A NESTED TABLE

I am trying to develop a university database with the help of nested tables, I have successfully created all other nested tables required and inserted data as well, but while inserting data into marks table I am facing problem of inconsistent datatype.
codes:
CREATE OR REPLACE TYPE MODULE_MARKS;
CREATE OR REPLACE TYPE MM_NT_TYPE AS TABLE OF REF MODULE_MARKS;
CREATE OR REPLACE TYPE MODULE_MARKS AS OBJECT
(
MODULE REF MODULE_T, MARKS_OBTAINED, TOTAL_MARKS, STATUS
)
CREATE TABLE MARK_TAB
(
student ref student_t,
modules_marks mm_nt_type
)
I am able to insert reference to student correctly but I want to insert data into module_marks.
Tried doing :
INSERT INTO MARK_TAB VALUES((SELECT REF(S) FROM STUDENT_TAB S WHERE
S.S_ID=1),
MM_NT_TYPE( MODULE_MARKS_T((SELECT REF (M) FROM MODULE_TAB M WHERE
M.MODULE_ID =1),
90,100,'PASS')));
this shoes the error ORA-00932. EXPECTED REFERENCE OF MODULE_MARKS_T GOT MODULE_MARKS_T.
It seems a familiar structure to me. Maybe I have created the same structure for one of my projects.
I think you are confused when inserting the record in the column having a type which is table of REF.
I have COURSES_TABLE_TYPE which is table of REF COURSES_T and courses table is table of COURSES_T;
I suggest you do the following:
INSERT INTO DEPARTMENT VALUES (
1,
COURSES_TABLE_TYPE(( -- REFs of single records delimited by comma
SELECT
REF(C)
FROM
COURSE C
WHERE
COURSE_ID = 1
),(
SELECT
REF(C)
FROM
COURSE C
WHERE
COURSE_ID = 2
))
);
MM_NT_TYPE is a collection of REF MODULE_MARKS whereas you are passing MODULE_MARKS objects and not references. Instead, you need to have a table containing containing MODULE_MARKS objects that you can reference:
CREATE TABLE module_marks_tab OF module_marks;
Then you can reference those objects. For example:
INSERT INTO mark_tab VALUES (
( SELECT REF(s) FROM students s WHERE id = 2 ),
MM_NT_TYPE(
( SELECT REF( m ) FROM module_marks_tab m WHERE m.module.id = 1 AND marks_obtained = 3 ),
( SELECT REF( m ) FROM module_marks_tab m WHERE m.module.id = 3 AND marks_obtained = 8 )
)
);
db<>fiddle

Conditionally insert multiple data rows into multiple Postgres tables

I have multiple rows of data. And this is just some made up data in order to make an easy example.
The data has name, age and location.
I want to insert the data into two tables, persons and locations, where locations has a FK to persons.
Nothing should be inserted if there already is a person with that name, or if the age is below 18.
I need to use COPY (in my real world example I'm using NPQSQL for .NET and I think that's the fastest way of inserting a lot of data).
So I'll do the following in a transaction (not 100% sure on the syntax, not on my computer right now):
-- Create a temp table
DROP TABLE IF EXISTS tmp_x;
CREATE TEMPORARY TABLE tmp_x
(
name TEXT,
age INTEGER,
location TEXT
);
-- Read the data into the temp table
COPY tmp_x (name, age) FROM STDIN (FORMAT BINARY);
-- Conditionally insert the data into persons
WITH insertedPersons AS (
INSERT INTO persons (name, age)
SELECT name, age
FROM tmp_x tmp
LEFT JOIN persons p ON p.name = tmp.name
WHERE
p IS NULL
AND tmp.age >= 18
RETURNING id, name
),
-- Use the generated ids to insert the relational data into locations
WITH insertedLocations AS (
INSERT INTO locations (personid, location)
SELECT ip.id, tmp.location
FROM tmp_x tmp
INNER JOIN insertedPersons ip ON ip.name = tmp.name
),
DROP TABLE tmp_x;
Is there a better/easier/more efficient way to do this?
Is there a better way to "link" the inserts instead of INNER JOIN insertedPersons ip ON ip.name = tmp.name. What if name wasn't unique? Can I update tmp_x with the new person ids and use that?

Oracle - Nested Table fetching results

I have a problem with nested tables. I don't know if I can fetch the result in the way I want them.
For example I have:
create type Name as Object(
firstname varchar2(20),
lastname varchar2(20))final;
create type Author as Object(
authorName Name);
create type Author_list as table of Author;
create table books(bookID int primary key, author Author_list) nested table author store as Author_nested;
When I fetch the result with:
select b.bookID, a.authorname.firstname||' '||a.authorname.lastname
from books b, table(b.author) a;
I am getting for each author a specific row. I want that for a specific bookID the authors to display in that row and separated with commas. Is that possible?
ex: bookID, authorname
1 , ab, cd, de
Yes, it is possible (one way is to use LISTAGG):
select b.bookID,
LISTAGG(a.authorname.firstname||' '||a.authorname.lastname, ',')
WITHIN GROUP(ORDER BY b.BookId) AS authorname
from books b, table(b.author) a
GROUP BY b.bookID

SQL Trigger to insert/update sysdate after insert or updating tuple in another table

I've got the following database schema:
Movie (MovieID, Title, Year, Score, Votes) Actor(ActorID, Name, RecentDate)
Casting (MovieID, ActorID, Ordinal)
I'm trying to write a trigger so whenever I insert a tuple or update a tuple in the Casting table, the recent date value using SYSDATE should be updated in the Actor table for the actorid that is being used to insert or update a tuple in the Casting table.
Here is my code:
CREATE OR REPLACE TRIGGER updateDate
BEFORE INSERT OR UPDATE ON CASTING
FOR EACH ROW
BEGIN
SELECT RECENTDATE
FROM ACTOR
UPDATE ACTOR
SET RECENTDATE = SYSDATE
WHERE ACTORID = :new.ACTORID;
END;
/
I'm new to SQL and I know I probably could write this in an easier way.
Any ideas how to get this working?
Thanks for all the help.

Oracle 10 trigger logical

I am creating a database of films, where you can insert Films(id, director,the year of publishing-integer...), Directors, Actors(id, fate of birth, date of death-dates)... I have a problem with triggers in it, because in the table actors i want to ensure, that when you you want to add a new actor his year of birth cannot be bigger that the year of film publishing. But with the trigger I have written, i cannot insert any new actor, because the date of birth cannot be compared to the films publishing year, because the film does not exist yet. And i cannot add any new film too, because i have the same trigger on directors-which is not working too, and the film has a foreign mandatory key-id director. It is a bit complicated, so I hope you will get what I mean
create or replace
trigger "XVIKD00"."DATUM_NARODENIA_HEREC"
BEFORE INSERT OR UPDATE
ON HERCI
FOR EACH ROW
DECLARE
l_ROK_VYDANIA filmy.ROK_VYD%TYPE;
BEGIN
SELECT FILMY.ROK_VYD
INTO l_ROK_VYDANIA
FROM FILMY
WHERE FILMY.ID_FILM = :new.ID_HEREC;
IF( (:new.dat_umr_her is not null) and( FILMY.ROK_VYD is not null)
extract( year from :new.dat_nar_her ) > l_ROK_VYDANIA )
THEN
RAISE_APPLICATION_ERROR(-2009,'Dátumy nie su v správnom časovom
slede');
END IF;
END;
You have a circular dependence between your tables, and this way you can't insert any records, because the others don't exist yet.
To handle this in a reasonable fashion you should have:
Movies
id
name
Publishing_Year
Director
id
name
birthDate
Actor
id
name
birthDate
This way, you can always create each one of those, without having any dependencies from the others.
Then when you want to say that some Director directed a Movie you would insert into a table like this:
movie_director
id
movie_id
director_id
When you want to say that some actor stared in a Movie you insert a record in a table like this:
movie_actor
id
movie_id
actor_id
And if you wanted to validate if the director or the actor is old enough to be in said movie, you would put the triggers that validate that in these two tables.