What I want to do is this:
select AlbumId from (
select Album.AlbumId, Sum(Track.UnitPrice) as Total from Album
inner join Track on Album.AlbumId = Track.AlbumId
group by Album.AlbumId
) tpt
where Total = (select max(Total) from tpt);
but am getting:
Table 'db.tpt' doesn't exist
-which probably makes sense. However, I am new to SQL and don't know why tpt goes out of scope in my where clause. How can I achieve this? I want to get the tuple with the Max total and extract the AlbumId.
Thanks!
Use a JOIN with subqueries.
select tpt.AlbumId from (
select Album.AlbumId, Sum(Track.UnitPrice) as Total from Album
inner join Track on Album.AlbumId = Track.AlbumId
group by Album.AlbumId
) tpt
JOIN (
select Sum(Track.UnitPrice) as Total from Album
inner join Track on Album.AlbumId = Track.AlbumId
group by Album.AlbumId
ORDER BY Total DESC
LIMIT 1
) maxtpt ON tpt.Total = maxtpt.Total
Related
I have a query that displays the total amount of matches won by individual teams in the database,
select t.name, count(*) 'Matches_Won'
from test.team t
inner join test.match_scores m on m.winner = t.id
group by t.name
order by Matches_Won desc;
Another query prints out the total number of Matches Played by the Individual Teams in the database,
select t.name, count(*) 'Matches_PLayed' from test.team t inner join test.results r on r.home_team = t.id or r.away_team = t.id group by t.name
order by Matches_Played desc;
Now, I am trying to combine these two queries, I want a table with three columns,
Team Name
Matches Played
Matches Won
I tried to union the two queries, but it didn't work. Anyone who can guide me on this?
This is the Team Table
This is the Match Scores Table. In this table, the columns "Home Team", "Away Team" represents the Goals scored by respective team and the "Winner" is the foreign key, referring to the Team Table.
This is the Results Table, where home_team and away_team are foreign keys referring to the Teams Table.
Union unions two result sets. You want to have both results, something like a merged.
The following statement isn't proved, but it should show you the idea of the solution. You have to join both, the results and the played games in one query.
select t.name, count(distinct m.id) 'Matches_Won', count(distinct r.id) 'Matches_PLayed'
from test.team t
left join test.match_scores m on m.winner = t.id
left join test.results r on r.home_team = t.id or r.away_team = t.id
group by t.name
order by Matches_Won, Matches_Played desc;
can you join them based on team_name instead of union?
select
matchesplayed.name ,Matches_Won,Matches_PLayed
from
(
select t.name, count(*) 'Matches_PLayed' from test.team t inner join test.results r on r.home_team = t.id or r.away_team = t.id group by t.name
) matchesplayed
LEFT JOIN (select t.name, count(*) 'Matches_Won'
from test.team t
inner join test.match_scores m on m.winner = t.id
group by t.name ) matchesown
ON matchesown.name = matchesplayed.name
order by 1
Now, if a team looses all the matches, they will also show up with null in matches won column(left join is used for that).
I have a rating system in my app. Now I'm trying to get all AVG results from the ratings. Every AVG result has a result (in text) that I need to grab from the rating_results table.
It looks like this:
select round(avg(rating_results.rating)) as ratingresult, count(*) as votes, score.question_nl,
(select result_nl from rating_results where rating_results.rating = ratingresult and rating_results.score_id = score.id) from score
inner join score_categories on score_categories.id = score.category_id
inner join rating ON score.id = rating.score_id
inner join rating_results on rating.rating_result_id = rating_results.id
inner join dog on dog.id = rating.ratable_id
where dog.breed_id = 201
group by score.question_nl
The problem I have is that I cannot use ratingresult in the subselect.
Query 1 ERROR: Reference 'ratingresult' not supported (reference to
group function)
I already tried a lot but can't figure out another way.
Could use some help here, thanks!
--EDIT
The rating result explains the rating. So if the AVG rating is 4 then in the rating_results table I can find what that rating means:
Instead of a select for column value you could use a subquery for avg in join
select t.ratingresult
, count(*) as votes
, score.question_nl
, rating_results.result_nl
FROM score
inner join score_categories on score_categories.id = score.category_id
inner join rating ON score.id = rating.score_id
inner join rating_results on rating.rating_result_id = rating_results.id
inner join dog on dog.id = rating.ratable_id
INNER JOIN (
select round(avg(rating_results.rating)) as ratingresult
, score.question_nl
from score
inner join rating ON score.id = rating.score_id
inner join rating_results on rating.rating_result_id = rating_results.id
group by score.question_nl
) t ON t.ratingresult = rating_results.rating
AND rating_results.score_id = score.id
AND score.question_nl = t.question_nl
where dog.breed_id = 201
group by score.question_nl, t.ratingresult
avoinding subquery
I'm creating a system that allows a user to search a database of photo albums images for a keyword, it's working great, the only issue is that I'm ordering relevancy by the amount of times that keyword appears in an album. I'm doing this using:
SELECT collections_ids.collection_id
FROM `keywords`
INNER JOIN collections_ids ON keywords.id = collections_ids.photo_id
WHERE keywords.`keyword` = 'trees'
GROUP BY collection_id
ORDER BY COUNT(*) DESC
As said, this works great.
The only issue is, when this is included in an "WHERE IN" query, it loses it's order and is returned randomly. For clarity, here is the query:
SELECT collections.id,
collections.title
images.img_small
FROM `collections`
INNER JOIN images ON images.id = collections.cover_photo
WHERE collections.`id` IN
(SELECT collections_ids.collection_id
FROM `keywords`
INNER JOIN collections_ids ON keywords.id = collections_ids.photo_id
WHERE keywords.`keyword` = 'trees'
GROUP BY collection_id
ORDER BY COUNT(*) DESC)
I've tried researching, and people have suggested using the FIELD function, but I don't see that working in this context.
Any suggestions?
you can use sub query as join and take it count(*) as order by like below
SELECT collections.id,
collections.title
images.img_small
FROM `collections`
INNER JOIN images ON images.id = collections.cover_photo
INNER JOIN
(SELECT distinct collections_ids.collection_id As collection_id,COUNT(*) as total
FROM `keywords`
INNER JOIN collections_ids ON keywords.id = collections_ids.photo_id
WHERE keywords.`keyword` = 'trees'
GROUP BY collection_id
) as A
ON A.collection_id =collections.collection_id
order by A.total
I'm supposed to write a query for this statement:
List the names of customers, and album titles, for cases where the customer has bought the entire album (i.e. all tracks in the album)
I know that I should use division.
Here is my answer but I get some weird syntax errors that I can't resolve.
SELECT
R1.FirstName
,R1.LastName
,R1.Title
FROM (Customer C, Invoice I, InvoiceLine IL, Track T, Album Al) AS R1
WHERE
C.CustomerId=I.CustomerId
AND I.InvoiceId=IL.InvoiceId
AND T.TrackId=IL.TrackId
AND Al.AlbumId=T.AlbumId
AND NOT EXISTS (
SELECT
R2.Title
FROM (Album Al, Track T) AS R2
WHERE
T.AlbumId=Al.AlbumId
AND R2.Title NOT IN (
SELECT R3.Title
FROM (Album Al, Track T) AS R3
WHERE
COUNT(R1.TrackId)=COUNT(R3.TrackId)
)
);
ERROR: misuse of aggregate function COUNT()
You can find the schema for the database here
You cannot alias a table list such as (Album Al, Track T) which is an out-dated syntax for (Album Al CROSS JOIN Track T). You can either alias a table, e.g. Album Al or a subquery, e.g. (SELECT * FROM Album CROSS JOIN Track) AS R2.
So first of all you should get your joins straight. I don't assume that you are being taught those old comma-separated joins, but got them from some old book or Website? Use proper explicit joins instead.
Then you cannot use WHERE COUNT(R1.TrackId) = COUNT(R3.TrackId). COUNT is an aggregate function and aggregation is done after WHERE.
As to the query: It's a good idea to compare track counts. So let's do that step by step.
Query to get the track count per album:
select albumid, count(*)
from track
group by albumid;
Query to get the track count per customer and album:
select i.customerid, t.albumid, count(distinct t.trackid)
from track t
join invoiceline il on il.trackid = t.trackid
join invoice i on i.invoiceid = il.invoiceid
group by i.customerid, t.albumid;
Complete query:
select c.firstname, c.lastname, a.title
from
(
select i.customerid, t.albumid, count(distinct t.trackid) as cnt
from track t
join invoiceline il on il.trackid = t.trackid
join invoice i on i.invoiceid = il.invoiceid
group by i.customerid, t.albumid
) bought
join
(
select albumid, count(*) as cnt
from track
group by albumid
) complete on complete.albumid = bought.albumid and complete.cnt = bought.cnt
join customer c on c.customerid = bought.customerid
join album a on a.albumid = bought.albumid;
Seems you are using count in the wrong place
use having for aggregate function
SELECT R3.Title
FROM (Album Al, Track T) AS R3
HAVING COUNT(R1.TrackId)=COUNT(R3.TrackId))
but be sure of alias because in some database the alias in not available in subquery ..
You should simplify your query. Take a look at this:
SELECT FirstName
, LastName
, Title
FROM (
SELECT C.FirstName
, C.LastName
, A.AlbumID
, A.Title
, COUNT(DISTINCT TrackID) as TracksInvoiced
FROM Customer C
INNER JOIN Invoice I
ON I.CustomerId = C.CustomerId
INNER JOIN InvoiceLine IL
ON I.InvoiceId = IL.InvoiceId
INNER JOIN Track T
ON T.TrackID = I
INNER JOIN Album A
ON A.AlbumID = T.AlbumID
GROUP BY C.FirstName, C.LastName, A.AlbumID, A.Title
) C
INNER JOIN (
SELECT AlbumID
, COUNT(TrackID) as TotalTracks
FROM Track
GROUP BY AlbumID
) A
ON C.AlbumID = A.AlbumID
AND TracksInvoiced = TotalTracks
I used two subselects, the first one counts invoiced tracks per customer and album and joins it with another subselect for each album and amount of tracks on it, only where the two counts are equal.
This one seems to be a little less complicated:
SELECT r.FirstName, r.LastName, r.Title FROM
(
SELECT C.FirstName as FirstName,
C.LastName as LastName,
A.Title as Title,
A.AlbumId as AlbumId,
COUNT(*) as count
FROM Customer C, Invoice I, InvoiceLine IL, Track T, Album A
WHERE C.CustomerId=I.CustomerId
AND I.InvoiceId = IL.InvoiceId
AND T.TrackId = IL.TrackId
AND A.AlbumId = T.AlbumId
GROUP BY C.CustomerId, A.AlbumId
) AS r
WHERE r.count IS IN
(
SELECT COUNT(*) FROM Track T
WHERE T.AlbumId = r.AlbumId
)
Tested the idea on a simpler basis and extended to your example so I don't give a guarantee that you can copy and paste and its working immediately...
I have a simple one-to-many relationship. One table is a list of albums, and the other a list of photos. Each photo can only be of one album, but an album contains many images.
Now I want to get a list of all the albums in a single query. The information I want is some values of the album itself (let's say the name of the album), the total image count in that album and some values of the first image.
I already have the total image count and the album name, but I am having some issues trying to get the first image values as well.
SELECT albums.id, albums.name, COUNT(photos.id) AS imageCount
FROM albums
LEFT JOIN photos ON albums.id = photos.albumid
GROUP BY name
ORDER BY id DESC
I have tried several approaches from other answers but I seem to be doing something wrong. It's especially confusing since I am using COUNT() as well.
I have created a sqlfiddle that has this query in it as well as a small sample database. So how do I also get some values of the first element of photos?
SELECT x.id
, x.name
, total
, y.id
, y.url
FROM
( SELECT a.*
, COUNT(p.id) total
, MIN(p.id) min_id
FROM albums a
LEFT
JOIN photos p
ON p.albumid = a.id
GROUP
BY a.id
) x
LEFT
JOIN photos y
ON y.id = x.min_id;
you can do by this query:
SELECT albums.id,
albums.name,
COUNT(photos.id) AS imageCount ,
(select url
from photos
where id =(select min(id)
from photos internal_photo
where albums.id = internal_photo.albumid )) as photo_url
FROM albums
LEFT JOIN photos ON albums.id = photos.albumid
GROUP BY name
ORDER BY id DESC
Im using the url format to get the first one, if you have a different format you need another join to get the first one.
SELECT A.*, P.url
FROM
(
SELECT albums.id, albums.name, COUNT(photos.id) AS imageCount
FROM albums
LEFT JOIN photos ON albums.id = photos.albumid
GROUP BY name
) A
LEFT JOIN (
SELECT `albumid`, MIN(`url`) as `url`
FROM photos
GROUP BY `albumid`
) P
ON A.id = P.`albumid`
ORDER BY id DESC
A more generic version free of string hassles would be:
SQL Fiddle Demo
SELECT *
FROM
(
SELECT albums.id, albums.name, COUNT(photos.id) AS imageCount
FROM albums
LEFT JOIN photos ON albums.id = photos.albumid
GROUP BY name
ORDER BY id DESC
) A
LEFT JOIN (
SELECT photos.`albumid`, photos.`url`
FROM photos
LEFT JOIN (
SELECT `albumid`, MIN(`id`) as `id`
FROM photos p1
GROUP BY `albumid`
) P1
ON photos.`albumid` = p1.`albumid`
AND photos.`id` = P1.`id`
) P
ON A.id = P.`albumid`
If you use MySQL as your database, you can run this query
SELECT albums.id, albums.name, photos.url, COUNT(photos.id) AS imageCount
FROM albums
LEFT JOIN photos ON albums.id = photos.albumid
GROUP BY name
ORDER BY id DESC
Because Grouping in MySQL always return the first row value. CMIIW.
But you can also try this query (only a nested subquery).
SELECT albums.id, albums.name, COUNT(photos.id) AS imageCount, (
SELECT photos.url
FROM photos
WHERE albums.id = photos.albumid
ORDER BY id ASC
LIMIT 1
)
FROM albums
LEFT JOIN photos ON albums.id = photos.albumid
GROUP BY name
ORDER BY id DESC