SQL ORDER BY number of rows? - sql

How do you ORDER BY number of rows found in another table? I have a table for animals (these are livestock animals) and another table for awards. When an animal wins an award, the award gets added to the awards table.
People want to be able to find the animals who have won the most awards (WHERE award type is 1), ordered from most awards to least. How do I ORDER BY how many awards they have if the awards are in a separate table each with their own row?
SELECT animals.id
FROM animals
LEFT JOIN awards ON animals.id = awards.animalid
WHERE awards.type = 1
ORDER BY...

You would seem to want GROUP BY:
SELECT a.id
FROM animals a LEFT JOIN
awards aw
ON a.id = aw.animalid AND aw.type = 1
GROUP BY a.id
ORDER BY COUNT(aw.animalid) DESC;

Related

Query to select related data from two tables in which one table has no related fields in third table

I have three tables in my Oracle db:
Peoples:
IdPerson PK
Name
Surname
Earnings:
IdEarning PK
IdPerson
EarningValue
Awards:
IdAward PK
IdPerson FK
AwardDescription
So one person can have many earnings, one earning or can have no any earnings. Also one person can have many awards, one award, or no any award.
I have to select Surname and AwardDescription but only for people who have any earnings, because it is possible to have some award but, also don't have any earning!
My problem is to make a correct group by statement. I use query posted below and I am selecting surname of person with a description of award, but it is duplicating for each row in Earnings for this person.
SELECT AwardDescription, Surname
FROM Awards
INNER JOIN People ON People.IdPerson= Awards.IdPerson
INNER JOIN Earnings ON Earnings .IdPerson= People.IdPerson;
How to group it and avoid duplicating rows for each earning of person?
One person can be in many rows, but with different awards.
You could add DISTINCT to your query:
SELECT DISTINCT AwardDescription, Surname
FROM Awards
INNER JOIN People ON People.IdPerson= Awards.IdPerson
INNER JOIN Earnings ON Earnings .IdPerson= People.IdPerson;
Or another option is to use EXISTS:
SELECT AwardDescription, Surname
FROM Awards
INNER JOIN People P ON P.IdPerson= Awards.IdPerson
WHERE EXISTS (
SELECT 1
FROM Earnings E
WHERE P.IdPerson = E.IdPerson);
Do a left outer join among the tables like
SELECT p.Surname, a.AwardDescription, e.EarningValue
FROM People p
LEFT JOIN Awards a ON p.IdPerson= a.IdPerson
LEFT JOIN Earnings e ON e.IdPerson= p.IdPerson
WHERE a.AwardDescription IS NOT NULL
OR e.EarningValue IS NOT NULL;

Query with aggregating data from 2 tables

I have three tables in my Oracle db:
Peoples:
IdPerson PK
Name
Surname
Earnings:
IdEarning
IdPerson
EarningValue
Awards:
IdAward PK
IdPerson FK
AwardDescription
A person can have many earnings.
An earning can have many or no any earnings.
A person can have many awards, one award, or no any award.
I want to make a query that will return 3 columns:
Surname
SUM of all EarningValue of person with this surname
COUNT of all Awards for this person
An important thing is that i also need to display: 0 value if person don't have any award or earning. There is a possibility that person have an award but don't have any earning.
Is it possible to make such query?
SELECT p.IdPerson,
p.Surname,
NVL(SUM(e.EarningValue), 0) as SumEarnings,
COUNT(a.IdAward) as CntAwards
FROM Peoples p
LEFT JOIN Earnings e ON p.IdPerson = e.IdPerson
LEFT JOIN Awards a ON p.IdPerson = a.IdPerson
GROUP BY p.IdPerson,
p.Surname;
What returns this:
SELECT p.Surname,
(SELECT NVL(SUM(e.EarningValue), 0)
FROM Earnings e WHERE e.IdPerson = p.IdPerson) as SumEarnings,
(SELECT COUNT(aIdAward)
FROM Awards a WHERE a.IdPerson = p.IdPerson) as CntAwards
FROM Peoples p
yes of-course it is possible.
you just need to join the tables using multiple join queries and then apply sum() function to get sum of earnings and Count() to count the no. of awards.
Try the below query:
SELECT P.Surname,
Sum(E.EarningValue)AS Total_Earnings,
Count(A.IdAward) AS total_awards
FROM Peoples P
LEFT JOIN Earnings E
ON P.IdPerson = E.IdPerson
LEFT JOIN Awards A
ON A.IdPerson = P.IdPerson
GROUP BY P.IdPerson;
Yes it is possible, you just have to join the tables
SELECT Peoples.Surname, SUM(Earnings.EarningValue) as Earnings, COUNT(Awards. IdPerson) as Awards
FROM Peoples
INNER JOIN Earnings
ON Peoples.IdPerson = Earnings.IdPerson
INNER JOIN Awards
ON Peoples.IdPerson = Awards.IdPerson
GROUP BY Peoples.IdPerson;

sql get a unique ID then count the number of tuples relating to that ID

Database Structure
MovieInfo (mvID, title, rating, year, length, studio)
DirectorInfo(directorID, firstname, lastname)
MemberInfo(username, email, password)
ActorInfo(actorID, firstname, lastname, gender, birthplace)
CastInfo(mvID*, actorID*)
DirectInfo(mvID*, directorID*)
GenreInfo(mvID*, genre)
RankingInfo(username*, mvID*, score, voteDate)
Query
I need to get the director with the largest number of comedy movies. (I'm also required to use the ALL operator). My understanding is getting the list of mvid where genre = 'Comedy" and directorid:
select mvid
from genreinfo
where genre = 'Comedy'
union all
select directorid
from directorinfo
;
But then how do I count the number of movies a specific director has? And how do I get that single one with the highest count of "comedy" movies?
You're on the right track. I'd recommend looking at JOINs.
I've provided a step-by-step answer on how to obtain the desired results. If you just want the final query, go down to step 5 and pick the one appropriate for your DBMS.
1: Selecting all comedy movie IDs:
SELECT mvid
FROM GenreInfo
WHERE genre = 'Comedy';
2: Selecting the directorIDs of those movies
SELECT directorID
FROM DirectInfo
JOIN GenreInfo
ON DirectInfo.mvID = GenreInfo.mvID
WHERE genre = 'Comedy';
3: Selecting the director name of those directors.
SELECT firstname
FROM DirectorInfo
JOIN DirectInfo
ON DirectorInfo.directorID = DirectInfo.directorID
JOIN GenreInfo
ON DirectInfo.mvID = GenreInfo.mvID
WHERE genre = 'Comedy';
4: Grouping that query by director to get number of movies:
SELECT firstname, COUNT(*) AS NumberOfMovies
FROM DirectorInfo
JOIN DirectInfo
ON DirectorInfo.directorID = DirectInfo.directorID
JOIN GenreInfo
ON DirectInfo.mvID = GenreInfo.mvID
WHERE genre = 'Comedy'
GROUP BY DirectorInfo.directorID;
5: Sort the results and get only the first one:
SELECT firstname, COUNT(*) AS NumberOfMovies
FROM DirectorInfo
JOIN DirectInfo
ON DirectorInfo.directorID = DirectInfo.directorID
JOIN GenreInfo
ON DirectInfo.mvID = GenreInfo.mvID
WHERE genre = 'Comedy'
GROUP BY DirectorInfo.directorID
ORDER BY NumberOfMovies
LIMIT 1;
If you're using SQL server, use TOP instead:
SELECT TOP 1 firstname, COUNT(*) AS NumberOfMovies
FROM DirectorInfo
JOIN DirectInfo
ON DirectorInfo.directorID = DirectInfo.directorID
JOIN GenreInfo
ON DirectInfo.mvID = GenreInfo.mvID
WHERE genre = 'Comedy'
GROUP BY DirectorInfo.directorID
ORDER BY NumberOfMovies;
You can use a join and group by to get the result.
select DirectorID,COUNT(mvid)
from DirectInfo d
inner join genreinfo g
ON d.mvid=g.mvid
where genre ='Comedy'
GROUP BY DirectorID
ORDER BY COUNT(mvid)
This is homework? Well, right now you are selecting a list of IDs, some of them representing directors, others representing movies. You notice that this is not at all what you are supposed to do, right?
What you want is a list of directors. So you select from the DirectorInfo table. You also want information about his movies (excatly: the number of movies of a certain kind). So you must join that information from MovieInfo. Now think about what else you need to glue together to get from director to their movies. Then think about how to glue in that genre criterium.
Once you have joined it all together, then you group your results. You want one record per director (instead of ane record per director and movie), so you make a group and count within that group.
I hope this helps you solve your task. Good luck!
select di.directorid, count(1) as 'no_of_comedy_movies'
from DirectorInfo di inner join join DirectInfo dri
on di.directorid = dri.directorid
inner join genreinfo gi
on gi.mvid = dri.mvid
where gi.genre = 'Comedy'
group by dri.directorID
order by no_of_comedy_movies

SQL select for average from another table

I spent a lot of time building this select, but Im not able to solve it. I have 2 tables. First table is called car and has PK (primary key) id_car and another columns name and so on. Second table is called rating and has colums id_rating (PK), id_car (FK) and rating_value (integer). As you suspect, one car can have more than one ranting. I want to select all cars and I want to know average rating to each car. Finally, I want to order the result by this average desc. I was trying things like this:
SELECT id_car, name, average
FROM car C, rating R
WHERE C.id_car = R.id_car
ORDER BY (average) (
SELECT AVG(rating_value) AS average
FROM rating R
WHERE C.id_car = R.id_car)
but it doesn't work.
For SQL Server; Also I suggest you to use JOIN instead of WHERE table1, table2..
SELECT C.id_car, name, AVG(rating_value) AS average
FROM car C JOIN rating R
ON C.id_car = R.id_car
GROUP By C.id_car, name
ORDER BY average DESC
This implements the aggregate function AVG() and then a GROUP BY the car id and name:
select c.id_car, c.name, avg(r.rating_value) aver
from car c
left join rating r
on c.id_car = r.id_car
group by c.id_car, c.name
order by aver desc
Using a LEFT JOIN will include all cars in the result even those which have no yet been rated.
SELECT C.name, AVG(R.rating_value)
FROM car C, rating R
WHERE C.id_car = R.id_car
GROUP BY C.name
ORDER BY AVG(R.rating_value) DESC
SELECT c.id_car, c.name,avg(r.rating_value) as rating
FROM car c
join rating r
on c.id_car = r.id_car
group by r.id_car
order by rating

help with a sql query joining 2 many-many tables

i want help how to solve this sql problem.
suppose i have 3 tables
Movie
ID
Name
Genre
ID
Name
Movie_Genre (this one is the link for many to many)
FK_MovieID
FK_GenreID
i want to select all the movies that are of genre 1 and genre 3
how is this possible?
i can only select the movies of 1 genre but not the movies that are of 2 genres using
SELECT Movie.ID, Movie.Name
FROM Movies
INNER JOIN Movie_Genre ON Movie_Genre.FK_MovieID=Movie.ID
AND Movie_Genre.FK_GenreID = 1
Use:
SELECT m.id,
m.name
FROM MOVIE m
JOIN MOVIE_GENRE mg ON mg.fk_movieid = m.id
AND mg.fk_genreid IN (1, 3)
GROUP BY m.id, m.name
HAVING COUNT(DISTINCT mg.fk_genreid) = 2
The last line is key to getting rows from both genre's - the DISTINCT means duplicate associations (IE: two instances of genre 1) will be ignored because they are false positives. But the count must equal the number of genres you are looking for.
But COUNT(DISINCT isn't supported by all databases. You should mention what you are using - if not by tag, then in the question... If the primary key for the MOVIE_GENRE table is both fk_movieid and fk_genreid, then it's not an issue. Next best thing would be that both the columns are in a unique constraint/index...