Oracle - Nested Table fetching results - sql

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

Related

SQL: combine two tables for a query

I want to query two tables at a time to find the key for an artist given their name. The issue is that my data is coming from disparate sources and there is no definitive standard for the presentation of their names (e.g. Forename Surname vs. Surname, Forename) and so to this end I have a table containing definitive names used throughout the rest of my system along with a separate table of aliases to match the varying styles up to each artist.
This is PostgreSQL but apart from the text type it's pretty standard. Substitute character varying if you prefer:
create table Artists (
id serial primary key,
name text,
-- other stuff not relevant
);
create table Aliases (
artist integer references Artists(id) not null,
name text not null
);
Now I'd like to be able to query both sets of names in a single query to obtain the appropriate id. Any way to do this? e.g.
select id from ??? where name = 'Bloggs, Joe';
I'm not interested in revising my schema's idea of what a "name" is to something more structured, e.g. separate forename and surname, since it's inappropriate for the application. Most of my sources don't structure the data, sometimes one or the other name isn't known, it may be a pseudonym, or sometimes the "artist" may be an entity such as a studio.
I think you want:
select a.id
from artists a
where a.name = 'Bloggs, Joe' or
exists (select 1
from aliases aa
where aa.artist = a.id and
aa.name = 'Bloggs, Joe'
);
Actually, if you just want the id (and not other columns), then you can use:
select a.id
from artists a
where a.name = 'Bloggs, Joe'
union all -- union if there could be duplicates
select aa.artist
from aliases aa
where aa.name = 'Bloggs, Joe';

creating the sql query for company supervisors

I have four tables
create table emp (emp_ss int, emp_name nvarchar(20));
create table comp(comp_name nvarchar(20), comp_address nvarchar(20));
create table works (emp_ss int, comp_name nvarchar(20));
create table supervises (spv_ss int, emp_ss int );
Here SUPRVISER_SS and EMP_SS are subset of SS. Now I have to find:
the name of all the companies who have more than 4 supervisors
I have made a query for the above problem but not sure whether it is correct or not
SELECT COMP_NAME , COUNT(EMP_SS) FROM WORKS
WHERE EMP_SS IN (SELECT DISTINCT SPV_SS FROM supervises)
GROUP BY COMP_NAME
HAVING COUNT(EMP_SS) > 4;
the name of supervisors who have the largest number of employees
but unable to get the required result of the above condition
SELECT SPV_SS, COUNT(*) max_ FROM supervises GROUP BY SPV_SS
You don't need to have a seperate table for supervisors unless they come with extra information that doesn't belong in the employee table, just add an extra field (foreign key) in Employee table that links to the primary key in the same table.
First question: select company just use a group by companyid clause and then check if the count of supervisors is larger than 4 for.
Second question: select count(empid) and supervisor, use group by supervisor clause and add order by clause on the count column
I explained the logic, as for the actual sql code, you're gonna have to figure that out yourself.

Oracle - Query about data in a collection of reference

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.

Json query vs SQL query using JSON in Oracle 12c (Performance)

I am using oracle 12c and Sql Developer with json
For this example I have the follow JSON:
{
"id": "12",
"name": "zhelon"
}
So I have created the follow table for this:
create table persons
id number primary key,
person clob,
constraint person check(person is JSON);
The idea is persist in person column the previous JSON and use a the follow query to get that data
SELECT p.person FROM persons p WHERE json_textvalue('$name', 'zhelon')
Talking about perfonce, I am intresting to extract some json field and add new a colum to the table to improve the response time (I don't know if that is possible)
create table persons
id number primary key,
name varchar(2000),
person clob,
constraint person check(person is JSON);
To do this:
SELECT p.person FROM persons p WHERE p.name = 'zhelon';
My question is:
What's the best way to make a query to get data? I want to reduce the response time.
Which query get the data faster ?
SELECT p.person FROM persons p WHERE json_textvalue('$name', 'zhelon')
or
SELECT p.person FROM persons p WHERE p.name = 'zhelon';
You can create a virtual column like this:
ALTER TABLE persons ADD (NAME VARCHAR2(100)
GENERATED ALWAYS AS (JSON_VALUE(person, '$name' returning VARCHAR2)) VIRTUAL);
I don't know the correct syntax of JSON_VALUE but I think you get an idea.
If needed you can also define a index on such columns like any other column.
However, when you run SELECT p.person FROM persons p WHERE p.name = 'zhelon';
I don't know which value takes precedence, p.person from JSON or the column.
Better use a different name in order to be on the safe side:
ALTER TABLE persons ADD (NAME_VAL VARCHAR2(100)
GENERATED ALWAYS AS (JSON_VALUE(person, '$name' returning VARCHAR2)) VIRTUAL);
SELECT p.person FROM persons p WHERE p.NAME_VAL= 'zhelon';

SQL: How to separate string values separated by commas?

I'm trying to create a relational database of all the movies I have watched.
I used IMDb to rate the movies I've seen and used the site's export capability to get the data in a .csv file which I uploaded to Microsoft Access. However, the "Genre" column is a many-to-many relationship that I am hoping to turn into a one-to-many relationship.
I would like to have a table called GENRE_ID that assigns each genre a numerical ID. Then I'd have another table where each instance would have the movie ID ("const"), line item number, and GENRE_ID.
So it might look like:
const line_item MOVIE_ID
tt0068646 1 1 (if MOVIE_ID: 1 = "crime")
tt0068646 2 2 (if MOVIE_ID: 2 = "drama")
Here's a link to the image of my database's current state. Thank you so much for your help. This is a project I'm doing to learn more on my own time.
Basically, when you have a one-to-many relationship, you should use a table for that relationship
In your case, I would recommend to have 3 table:
Film table : contains information like your current table ,except Genres
Genre table : contains (at least) Id and Name
Film_Genre table : contains Film_Id, GenreId.
For example
In your genre table, your data would be
row 1: Id =1 , Name = "Crime"
row 2: Id = 2, Name = drama,
and so on
your Film_Genre table would be something like:
row1: Film_Id = tt0068646, GenreId = 1,
row2: Film_Id = tt0068646, GenreId = 2
row3: Film_Id = tt0082971, GenreId = 2
and so on
(I supposed that you use "const" column as Id of Film table, if not, you should have your own Id)
Of course, it take you a litte bit effort to transform your current database to this database.
Some notes on a way to a solution.
A table of genres
ID Genre
1 Action
2 Adventure
3 Thriller
4 War
An import table
Const GenreList
tt00 Action, Adventure, Thriller, War
A query
SELECT ti.Const, ti.GenreList, tg.Genre
FROM Imports as ti, Genres as tg
WHERE ti.GenreList Like "*" & tg.Genre & "*"