Here is my film table:
FILM (Catalog_Num, Format, Title, Year, Number_Discs, Rating, Timing, Genre)
I want to concatenate the genre column if the year is before 1970 and it cannot be repeated,
for example, if the genre is Romantic --> (Classic Romance) its ok.
but is the genre is already Classic, it should remain Classic rather than (Classic Classic)
after that, I have to list id, title, and genre of all classic film.
Here is what I tried:
select genre|| 'Classic'
from film where (year <1970 and genre not in ('Classic'));
select film_id, title, genre
from inventory, film
where film.catalog_num = inventory.catalog_num and genre like '%Classic%';
But the output only shows all the genre in classic type, instead of romance classics.
Further, I have to finish in one query, but I don't know how to combine them.
Use a subquery to manipulate the data and feed that into your main query:
with films as (
select catalog_num
, title
, case
when (year <1970 and genre not in ('Classic'))
then 'Classic ' || genre
else genre end as genre
from film
)
select inventory.film_id
, films.title
, films.genre
from inventory
join films on films.catalog_num = inventory.catalog_num
where films.genre like '%Classic%';
Your question says you want Romantic --> (Classic Romance) but your posted code has genre||'Classic which is the other way round. I have changed the code to generate 'Classic Romance'.
Note: you haven't aliased the columns in the second query's projection, so I had to guess which columns come from film and which from inventory. You will need to correct any wrong guess.
If you only want your definition of class films, then you don't have to munge the genre. Just do:
select i.film_id, f.title, f.genre
from inventory i join
films f
on f.catalog_num = i.catalog_num
where f.genre like '%Classic%' or f.year < 1970;
If you still want "Classic" in the genre:
select i.film_id, f.title,
(case when f.year < 1970 and f.genre <> 'Classic'
then 'Classic ' || f.genre
else f.genre
end) as genre
from inventory i join
films f
on f.catalog_num = i.catalog_num
where f.genre like '%Classic%' or f.year < 1970;
Your question is a little vague on whether "Classic" can be part of a genre name rather than the entire name. So you might want:
(case when f.year < 1970 and f.genre not like '%Classic%'
then 'Classic ' || f.genre
else f.genre
end) as genre
Note that such comparisons are usually case-sensitive in Oracle, so you might need to take uppercase/lowercase into account as well.
Related
I need to make a single SQL request like this:
SELECT genres, count(*) FROM books WHERE genres LIKE 'Fiction%'
But I need to use many keyword like 'Nonfiction%', 'Historical' ect. The output should be a table:
Fiction 8654
Nonfiction 6543
Historical 2344
What SQL request I have to use to get this result?
Hopefully, you can just do:
SELECT genres, count(*)
FROM books
GROUP BY genres;
In fact, you could just do this if you had a table called BookGenres with one row per book and per genre. That is the right way to store this data.
In this case you appear to be looking only for the first genre in the list. You can use case:
select (case when genres like 'Fiction%' then 'Fiction'
when genres like 'Nonfiction%' then 'Nonfiction'
when genres like 'Historical%' then 'Historical'
else 'Other'
end) as genre, count(*)
from books
group by (case when genres like 'Fiction%' then 'Fiction'
when genres like 'Nonfiction%' then 'Nonfiction'
when genres like 'Historical%' then 'Historical'
else 'Other'
end);
You could use group by
SELECT genres, count(*)
FROM books
GROUP BY genres
or for a set of values
SELECT genres, count(*)
FROM books
WHERE genres in ( 'Fiction', 'Nonfiction', 'Historical')
GROUP BY genres
I have a problem with a query, that i can't figure out. Have tried for some time, but I just can't figure it out. Would be a great deal of help if you could help me. So... I have 4 tables:
cars - ID, make, model, plate_number, price, type, year, owner_ID
persons - ID, name, surname, pers_code
insurance_data - company_ID, car_ID, first_date, last_date
companies - ID, title
My query so far is..
SELECT cars.plate_number, persons.name, persons.surname, insurance_data.last_date
FROM cars,persons,insurance_data
WHERE cars.owner_ID = persons.ID AND cars.ID = insurance_data.car_ID
This outputs cars plate number, owner of the car, and the last date of the car's insurance. But the problem is that there's two cars that have two end dates of insurance, so in the output there's two entries for same car and with both insurance end dates. What i need is that there would be only one entry for each car and corresponding insurance end date should be the latest.
I know this is pretty basic, but i'm a first year student of databases, and this is one of my first assignments. Thanks in advance
(1) Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
(2) Use table aliases!
The answer to your question is DISTINCT ON:
SELECT DISTINCT ON (c.plate_number) c.plate_number, p.name, p.surname, id.last_date
FROM cars c JOIN
persons p
ON c.owner_ID = p.ID JOIN
insurance_data id
ON c.ID = id.car_ID
ORDER BY c.plate_number, id.last_date DESC;
I need to find all titles of films that have greater replacement cost than some R rating film.
film table has...
film_id, title, description, release_year, language_id, original_language_id, rental_duration, rental_rate, length, replacement_cost, rating, special_features, last_update
This is not working...
SELECT
title
FROM film
WHERE replacement_cost > (SELECT
replacement_cost
FROM film
WHERE rating = 'R');
SELECT title
FROM film
WHERE replacement_cost >
(SELECT MAX(replacement_cost)
FROM film
WHERE rating = 'R');
You need aggregation of some kind to make the subselect a scalar value. Using MAX() in your query would give you the highest replacement_cost of a rated R film.
To get the replacement_cost of a particular film then you need to do the same thing but modify your where statement to be the film you want. say you know the film_id then you could do:
SELECT title
FROM film
WHERE replacement_cost >
(SELECT replacement_cost
FROM film
WHERE film_id = 123);
Note I took off MAX() because when using the primary key or criteria that will choose a single scalar value (1 column 1 row) from the table you don't actually have to use aggregation.
Title may not make sense so I will provide some context.
I have a table, call it Movies.
A movie tuple has the values: Name, Director, Genre, Year
I'm trying to create a query that allows me to return all Directors who have never released two consecutive Horror films with more than 4 years apart.
I'm not sure where I'd begin but I'm trying to start off by creating a query that given some specific year, returns the next minimum year, so that I can check if the difference between these two is less than 4, and keep doing that for all movies.
My attempt was:
SELECT D1.Director
FROM Movies D1
WHERE D1.Director NOT IN
(SELECT D2.Director FROM Director D2
WHERE D2.Director = D1.Director
AND D2.Genre = 'Horror'
AND D1.Genre = 'Horror' AND D2.Year - D1.Year > 4
OR D1.Year - D2.Year > 4)
which does not work for obvious reasons.
I've also had a few attempts using joins, and it works on films that follow a pattern such as 2000, 2003, 2006, but fail if more than 3 films.
You could try this:
Select all data, and use lag or lead to return the last or next year. After that look at the difference between the two.
WITH TempTable AS (
SELECT
Name,
Director,
Genre,
Year,
LAG(Year) OVER (PARTITION BY Name, Director, Genre ORDER BY Year ASC) AS 'PriorYear'
FROM
Movies
WHERE
Genre = 'Horror'
)
SELECT
Name,
Director
FROM
TempTable
GROUP BY
Name,
Director
HAVING
MAX(Year-PriorYear) < 2
Try this:
SELECT * FROM (
SELECT director, min(diff) as diff FROM (
SELECT m1.director, m1.year as year1, m2.year as year2, m2.year-m1.year as diff
FROM `movies` m1, movies m2
WHERE m1.director = m2.director and m1.name <> m2.name and m1.year<=m2.year
and m1.genre='horror' and m2.genre='horror'
) d1 group by director
) d2 WHERE diff>4
First, in the inner Select it will list all movie pairs of directors' horror movies with year difference calculated, then minimum of these are selected (for consecutiveness), then longer than 4 years differences are selected...
I have to write a query which returns the price of books greater than the average price for books of similar type. So, I did this using the below query:
select title
from titles
where price >
(
select avg(price)
from titles
group by type
)
However it throws this error:
subquery returned more than 1 value
It is understandable that > cannot be used for a list of values. But I wanted to know the way I can solve this. Please let me know the query I need to use. The DB is pubs
titles table:
title_id , title, type, price, advance, notes, sales
so I need to get the title with price > average (price) of similar types
The key is to use the type from the main query to filter the type in the subquery.
SELECT t.title
FROM titles t
WHERE t.price > (SELECT AVG(t2.price)
FROM titles t2
WHERE t2.type = t.type)
You have more than one type, so each type is returning an average.
You can look into the SOME|ANY or ALL operators to look at the list of items
If you were looking for the titles whose prices are higher than all of the average types, An example of this would be:
SELECT title
FROM titles
WHERE price > ALL
(
SELECT AVG(price)
FROM titles
GROUP BY type
)
You could similarly change ALL to SOME or ANY to suit your needs.
select title
from titles
where price >
(select avg(price) from titles)
The above query assumes that you want the average of all title prices to compare against. This will return a scalar value and allow your query to succeed.
You need to link types from subquery and main query, example:
select
a.title
from
titles a
where
a.price > ( select avg(b.price) from titles b where a.type = b.type group by b.type)