Two statements in one query - sql

I want to select these pieces of information with 1 query and a subquery. How could I mix these statements?
SELECT
name, movie_id, type
FROM
Movie, Oscar
WHERE
rating = 'G'
AND type = 'BEST-PICTURE'
SELECT *
FROM Oscar
WHERE year IN (SELECT MAX(year) FROM Oscar)

Are you just trying to get all the oscars from the most recent year?
Without you showing us your table structures, I'm just guessing here - try something like this:
SELECT
m.name, m.movie_id, m.type
FROM
Movie m
INNER JOIN
Oscar o ON m.Movie_Id = o.Movie_Id
WHERE
m.rating = 'G'
AND m.type = 'BEST-PICTURE'
AND o.Year = (SELECT MAX(Year) FROM Oscar)

You can just use a Subquery, which is like 2 statement in one query.

Related

SQL Collect duplicates to one place? PostgreSQL

Sorry I'm new here and I'm also new with SQL and can't really explain my problem in the title...
So I have a TV show database, and there I have a Genre column, but for a TV show there are multiple Genres stored, so when I'm selecting all my TV Shows how can I combine them?
It needs to look like this:
https://i.stack.imgur.com/3EhBj.png
So I have to combine the string together, here is my code so far what I wrote:
SELECT title,
year,
runtime,
MIN(name) as name,
ROUND(rating, 1) as rating,
trailer,
homepage
FROM shows
JOIN show_genres
on shows.id = show_genres.show_id
JOIN genres
on show_genres.genre_id = genres.id
GROUP BY title,
year,
runtime,
rating,
trailer,
homepage
ORDER BY rating DESC
LIMIT 15;
I also have some other stuff here, that's my exerciese tasks! Thanks!
Also here is the relationship model:
https://i.stack.imgur.com/M89ho.png
Basically you need string aggregation - in Postgres, you can use string_agg() for this.
For efficiency, I would recommend moving the aggregation to a correlated subquery or a lateral join rather than aggregating in the outer query, so:
SELECT
s.title,
s.year,
s.runtime,
g.genre_names,
ROUND(s.rating, 1) as rating,
s.trailer,
s.homepage
FROM shows s
LEFT JOIN LATERAL (
SELECT string_agg(g.name, ', ') genre_names
FROM show_genres sg
INNER JOIN genres g ON g.id = sg.genre_id
WHERE sg.show_id = s.id
) g ON 1 = 1
ORDER BY s.rating DESC
LIMIT 15

Counting percentage of record from all records of given owner

I have owners and cars table.
I want to compute single car's price contribution to all cars that owner own.
In same query i have to compute price contribution to sum of every car's price so i do it like
student_37.cars.price::decimal/((SELECT SUM(price::decimal)
But in the same query grouping by in select does not work because i do not have any connection to proper record :/ Any tips?
entire query but i know it does not make a sense
SELECT
name,
student_37.cars.id AS car_id,
CONCAT((ROUND(student_37.cars.price::decimal/((SELECT SUM(price::decimal)
FROM student_37.cars))*100)),'%'
) AS percentage,
(student_37.cars.price::decimal/(SELECT SUM(PRICE) FROM student_37.cars GROUP BY owner_id))
FROM student_37.owners
JOIN
student_37.cars
ON
student_37.owners.id=student_37.cars.owner_id
I'm not sure to fully understand what you are trying to achieve, but this following query may help you or may be the solution :
SELECT
o.name,
c.id as car_id,
ROUND((c.price/t.total)*100, 2) AS percentage
FROM
owner o
JOIN car c ON o.id = c.owner_id
JOIN (
SELECT c.owner_id, SUM(c.price) AS total
FROM car c
GROUP BY c.owner_id
) t ON t.owner_id = o.id
SEE DEMO HERE
You should use window functions:
SELECT o.name, c.id as car_id,
ROUND((c.price/ SUM(c.price) OVER (PARTITION BY c.owner_id)) * 100, 2) AS percentage
FROM owner o JOIN
car c
ON o.id = c.owner_id;
They are more efficient than a JOIN/GROUP BY combination.

SQL Server : multiple transactions

select
STUDIO.NAME, MOVIE.TITLE, MOVIE.YEAR
from
STUDIO
join
MOVIE on STUDIO.NAME = MOVIE.STUDIONAME
where
MOVIE.YEAR >= ALL (select MOVIE.YEAR from MOVIE)
I have this code which give me as a result the year of the last film, it's title and the name of the studio, which make the movie.
How can I rewrite this code, so I can get the last produced movie by each studio, not only by one?
Try:
SELECT a.NAME,
a.TITLE,
a.YEAR
FROM (select s.NAME,
m.TITLE,
m.YEAR,
ROW_NUMBER()OVER(PARTITION BY s.NAME ORDER BY m.YEAR DESC ) as rnk
from STUDIO s
join MOVIE m on s.NAME = m.STUDIONAME) a
WHERE a.rnk = 1
SELECT *
FROM (
SELECT STUDIO.NAME, MOVIE.TITLE, MOVIE.YEAR
from
STUDIO
join
MOVIE on STUDIO.NAME = MOVIE.STUDIONAME
ORDER BY MOVIE.YEAR DESC
) AS newTable
GROUP BY newTable.NAME
You might try something like
select
studio.name,
movie.title,
movie.year
from
studio
inner join movie on
studio.name = movie.studioname
inner join
(
select
movie.studioname
max(movie.year) year
from
movie
) t1 on
t1.studioname = studio.studioname and
t1.year = movie.year
Note that there are limitations to the way you have written your query:
There could be multiple movies in the same year - which one is the latest? You would need a date column for that or something that that affect
Also you are using varchar/chars to join on which is really bad practice since you have to do a string comparison on each match. It would be better to use id - integers - which give better performance
The answer above is fine for finding the most recent year a studio published a movie, however if you need the title too, using that method you'll need to use some form of subselect to get the largest year (and so the most recent) by studio name, and then bring in the title based on this.
The below does both in a fairly succinct fashion using a CROSS APPLY:
SELECT
S.NAME,
MM.TITLE
MM.YEAR
FROM STUDIO S
CROSS APPLY
(SELECT TOP 1 TITLE, YEAR FROM MOVIE M
WHERE M.STUDIONAME = S.STUDIO
ORDER BY M.YEAR DESC) MM
1st Edit: Added context
2nd Edit: Added edit notes.
What do you mean "not only by one"?
Normally you do such queries using aggregate functions:
select STUDIO.NAME, MOVIE.TITLE, MAX( MOVIE.YEAR )
from STUDIO
join MOVIE on STUDIO.NAME = MOVIE.STUDIONAME
Group by STUDIO.NAME, MOVIE.TITLE
Is this what you need?

SQL aggregate query error

I have 3 tables like this
player(id,name,age,teamid)
team(id,name,sponsor,totalplayer,totalchampion,boss,joindate)
playerdetail(id,playerid,position,number,allstar,joindate)
I want to select teaminfo include name,sponsor,totalplayer,totalchampion,boss,
the average age of the players, the number of the allstar players
I write the t-sql as below
SELECT T.NAME,T.SPONSOR,T.TOTALPLAYER,T.TOTALCHAMPION,T.BOSS,T.JOINDATE,
AVG(P.AGE) AS AverageAge,COUNT(D.ALLSTAR) As AllStarPlayer
FROM Team T,Player P,PlayerDetail D
WHERE T.ID=P.TID AND P.ID=D.PID
but it doesn't work, the error message is
'Column 'Team.Name' is invalid in the select list because it is not
contained in either an aggregate function or the GROUP BY clause.'
Who can help me?
Thx in advance!
Add
GROUP BY
T.NAME,T.SPONSOR,T.TOTALPLAYER,T.TOTALCHAMPION,T.BOSS,T.JOINDATE
In most RDBMS (except MySQL which will guess for you), a column must be either aggregated (COUNT, AVG) or in the GROUP BY
Also, you should use explicit JOINs.
This is clearer, less ambiguous and more difficult to bollix your code
SELECT
T.NAME, T.SPONSOR, T.TOTALPLAYER, T.TOTALCHAMPION, T.BOSS, T.JOINDATE,
AVG(P.AGE) AS AverageAge,
COUNT(D.ALLSTAR) As AllStarPlayer
FROM
Team T
JOIN
Player P ON T.ID=P.TID
JOIN
PlayerDetail D ON P.ID=D.PID
GROUP BY
T.NAME, T.SPONSOR, T.TOTALPLAYER, T.TOTALCHAMPION, T.BOSS, T.JOINDATE;
Given that you want this data per team, and team.ID uniquely identifies team, I suggest the following:
SELECT max(T.NAME) As TeamName,
max(T.SPONSOR) As Sponsor,
max(T.TOTALPLAYER) As TotalPlayers,
max(T.TOTALCHAMPION) As TotalChampions,
max(T.BOSS) As Boss,
max(T.JOINDATE) As JoinDate,
AVG(P.AGE) AS AverageAge,
COUNT(D.PID) As AllStarPlayer
FROM Team T
join Player P on T.ID=P.TID
left join PlayerDetail D on P.ID=D.PID and D.ALLSTAR = 'Y'
group by T.ID
Use:
SELECT T.NAME,T.SPONSOR,T.TOTALPLAYER,T.TOTALCHAMPION,T.BOSS,T.JOINDATE,
AVG(P.AGE) AS AverageAge,COUNT(D.ALLSTAR) As AllStarPlayer
FROM Team T
JOIN Player P ON T.ID = P.TEAMID
JOIN PlayerDetail D ON P.ID = D.PLAYERID
GROUP BY T.NAME,T.SPONSOR,T.TOTALPLAYER,T.TOTALCHAMPION,T.BOSS,T.JOINDATE

SQL Query Help Part 2 - Add filter to joined tables and get max value from filter

I asked this question on SO. However, I wish to extend it further. I would like to find the max value of the 'Reading' column only where the 'state' is of value 'XX' for example.
So if I join the two tables, how do I get the row with max(Reading) value from the result set. Eg.
SELECT s.*, g1.*
FROM Schools AS s
JOIN Grades AS g1 ON g1.id_schools = s.id
WHERE s.state = 'SA' // how do I get row with max(Reading) column from this result set
The table details are:
Table1 = Schools
Columns: id(PK), state(nvchar(100)), schoolname
Table2 = Grades
Columns: id(PK), id_schools(FK), Year, Reading, Writing...
I'd think about using a common table expression:
WITH SchoolsInState (id, state, schoolname)
AS (
SELECT id, state, schoolname
FROM Schools
WHERE state = 'XX'
)
SELECT *
FROM SchoolsInState AS s
JOIN Grades AS g
ON s.id = g.id_schools
WHERE g.Reading = max(g.Reading)
The nice thing about this is that it creates this SchoolsInState pseudo-table which wraps all the logic about filtering by state, leaving you free to write the rest of your query without having to think about it.
I'm guessing [Reading] is some form of numeric value.
SELECT TOP (1)
s.[Id],
s.[State],
s.[SchoolName],
MAX(g.[Reading]) Reading
FROM
[Schools] s
JOIN [Grades] g on g.[id_schools] = s.[Id]
WHERE s.[State] = 'SA'
Group By
s.[Id],
s.[State],
s.[SchoolName]
Order By
MAX(g.[Reading]) DESC
UPDATE:
Looking at Tom's i don't think that would work but here is a modified version that does.
WITH [HighestGrade] (Reading)
AS (
SELECT
MAX([Reading]) Reading
FROM
[Grades]
)
SELECT
s.*,
g.*
FROM
[HighestGrade] hg
JOIN [Grades] AS g ON g.[Reading] = hg.[Reading]
JOIN [Schools] AS s ON s.[id] = g.[id_schools]
WHERE s.state = 'SA'
This CTE method should give you what you want. I also had it break down by year (grade_year in my code to avoid the reserved word). You should be able to remove that easily enough if you want to. This method also accounts for ties (you'll get both rows back if there is a tie):
;WITH MaxReadingByStateYear AS (
SELECT
S.id,
S.school_name,
S.state,
G.grade_year,
RANK() OVER(PARTITION BY S.state, G.grade_year ORDER BY Reading DESC) AS ranking
FROM
dbo.Grades G
INNER JOIN Schools S ON
S.id = G.id_schools
)
SELECT
id,
state,
school_name,
grade_year
FROM
MaxReadingByStateYear
WHERE
state = 'AL' AND
ranking = 1
One way would be this:
SELECT...
FROM...
WHERE...
AND g1.Reading = (select max(G2.Reading)
from Grades G2
inner join Schools s2
on s2.id = g2.id_schools
and s2.state = s.state)
There are certainly more.