Getting content and count from SQL at same time - sql

I've got 2 tables, albums and pictures...
pictures has relation to albums via fk_albumID.
Now want im trying is to select all from albums, and at the same time count how many pictures that has relation to albums...
I tried with:
SELECT *, (SELECT COUNT(*) FROM pictures WHERE pictures.fk_albumID = albums.albumID) AS albumCount FROM pictures, albums
But this first of all dont return any results if theres no pictures at all...
And then it repeats results according to count.
So if albums has 3 pictures, then i will get the album 3 times in my list, when i bind it to a Repeater.
And i tried:
SELECT COUNT(albums.albumID) AS albumCount, albums.albumName, albums.albumID FROM albums INNER JOIN pictures ON pictures.fk_albumID = albums.albumID GROUP BY albums.albumID, albums.albuName
But this only shows albums that has pictures...

You were close though. All you need is go from an INNER JOIN to an OUTER JOIN
SELECT COUNT(billeder.album_id) AS AlbumSize,
albums.album_name,
albums.album_id
FROM albums
LEFT OUTER JOIN billeder
ON billeder.album_home = albums.album_id
GROUP BY albums.album_id, albums.album_name

You can use a sub-query:
SELECT p.PicCount AS AlbumSize,
albums.album_name,
albums.album_id
FROM albums a
INNER JOIN billeder b
ON b.album_home = a.album_id
LEFT JOIN
(
SELECT count(*) PicCount, fk_albumid
FROM pictures
GROUY BY fk_albumid
) p
on a.album_id = p.fk_albumid

SELECT t1.album_title, isnull(sum(flag),0) AS PicCount
FROM albums AS t1
LEFT JOIN
(
SELECT *, 1 AS Flag
FROM pictures) AS t2
ON t1.fk_albumID = t2.fk_albumID
GROUP BY t1.album_title
Link to SQL Fiddle

SELECT (SELECT COUNT(1)
FROM billeder
WHERE billeder.album_home = albums.album_id) albumCount,
albums.album_name,
albums.album_id
FROM albums

select
AL.album_name,
AL.albumID,
(select count(*) from
ALBUMS AL1,
PICTURES PIC1
where AL1.albumID = PIC1.albumID) as CNT_ALBUMID
from
ALBUMS AL
Have a try

Related

Get Average in SQL Through Join

I'm just playing around with SQL and I'm trying to do the following.
I have 2 tables and here is their structure:
Movies_metadata Movies
ratings table:
Ratings
As there are many ratings for one movie, what I'd like to do is get the avg rating per movie and have it display next to the title which is only available in the Metadata table.
This is as far as I got but obviously the issue with my SELECT statement is that it'll return the average of all movies and display it for each record:
SELECT
(SELECT
AVG(rating)
FROM
`movies-dataset.movies_data.ratings`) AS rating_avg,
metadata.title,
metadata.budget,
metadata.revenue,
metadata.genres,
metadata.original_language,
metadata.release_date
FROM
`movies-dataset.movies_data.Movies_metadata` AS metadata
INNER JOIN `movies-dataset.movies_data.ratings` AS ratings
ON metadata.id = ratings.movieId
LIMIT 10
Here is an example of the result:
Result
I'm thinking I can potentially use a GROUP BY but when I try, I get an error
Appreciate the help!
The following should work:
SELECT movies_metadata.title, AVG(ratings.rating)
FROM movies_metadata
LEFT JOIN ratings ON movies_metadata.id = ratings.movieID
GROUP BY movies_metadata.title
You can swap movies_metadata.title by movies_metadata.id if not unique.
The LIMIT function and GROUP function might conflict with each other. Try getting the average rating as part of the inner join like this:
SELECT
ratings.averagerating,
metadata.title,
metadata.budget,
metadata.revenue,
metadata.genres,
metadata.original_language,
metadata.release_date
FROM `movies-dataset.movies_data.Movies_metadata` AS metadata
INNER JOIN (SELECT movieId, AVG(rating) averagerating FROM `movies-dataset.movies_data.ratings` GROUP by movieId) AS ratings
ON metadata.id = ratings.movieId
ORDER BY ratings.averagerating
LIMIT 5
Maybe try something like:
Select m.movieID, (r.rate_sum / r.num_rate) as avg_rating
From your_movies_table m
Left Join (select movie_id, sum(rating) as ‘rate_sum’, count(rating) as ‘num_rate’
From your_ratings_table
Group by movie_id) r
On m.movie_id = r.movie_id
I'm using a left join because I'm not sure if all movies have been rated at least once.

SQL top 10 results in nested query

hope someone can help me produce a nested query. Does not have to be efficient, just simple to follow.
I am looking to "Find the top 10 albums that have the greatest number of played tracks"
I have the following tables:
Album which has GRid and Title
AlbumTrack which has GRid and ISRC
Track which has ISRC and PlayCount
Ive currently got:
SELECT TOP 10 Album.Title
FROM Album
WHERE Grid IN
(SELECT AlbumTrack.GRid
FROM AlbumTrack
WHERE ISRC IN
(SELECT Track,ISRC
FROM TRACK
WHERE Track.ISRC = SUM(Track.PlayCount)
ORDER BY Track.PlayCount));
Any thoughts?
Using Join
SELECT Title
FROM (
SELECT Album.Title,
DENSE_RANK() OVER (ORDER BY PlayCount) AS RN
FROM Album
INNER JOIN AlbumTrack
ON Album.Grid = AlbumTrack.Grid
INNER JOIN
( SELECT ISRC, SUM(PlayCount) AS PlayCount
FROM TRACK
GROUP BY ISRC
)AS TRACK
ON AlbumTrack.ISRC=TRACK.ISRC
) AS T
WHERE RN<=10
try this query :
SELECT TOP 10 Album.Title FROM Album
JOIN AlbumTrack ON Album.Grid = AlbumTrack.GRid
JOIN (SELECT Sum(PlayCount) as NumberOfPlay , ISRC TRACK
GROUP BY AlbumTrack.ISRC
) as Track ON AlbumTrack.ISRC = Track.ISRC
ORDER BY Track.NumberOfPlay

Trouble with an aggregate SQL statement

This link will show you my schema and the contents of all tables involved.
My goal is to, using a single Select statement, display the name of every artist and sort by the number of "Rock" songs they have even for the artists that do not have any, in order of fewest to most. Here is what I tried, and it obviously did not work.
SELECT
Musical_genre.musical_genre_id,
COUNT(Musical_genre.musical_genre_id) AS nr_rocksongs
FROM
Musical_genre
JOIN
Album ON Album.musical_genre_id = Musical_genre.musical_genre_id
JOIN
Recording_artist ON Album.recording_artist_id = Recording_artist.recording_artist_id
GROUP BY
Album.recording_artist_id, Recording_artist.artist_name, Musical_genre.musical_genre_id
ORDER BY
nr_rocksongs ASC
Any ideas what I missed to get the results I am looking for? All help is greatly appreciated.
Remove the Musical_genre.musical_genre_id from group by and add the artist_name in select
SELECT Musical_genre.musical_genre_id, Recording_artist.artist_name,
COUNT(Musical_genre.musical_genre_id) AS nr_rocksongs
FROM Musical_genre
JOIN Album ON Album.musical_genre_id = Musical_genre.musical_genre_id
JOIN Recording_artist ON Album.recording_artist_id = Recording_artist.recording_artist_id
GROUP BY Musical_genre.musical_genre_id, Recording_artist.artist_name
ORDER BY nr_rocksongs ASC
You need to start with the artist and left join the album and genre.
SELECT
ra.artist_name,
mg.musical_genre_id,
mg.musical_genre,
COUNT(mg.musical_genre_id) AS nr_rocksongs
FROM
Recording_artist ra
LEFT JOIN Album a ON
a.recording_artist_id = ra.recording_artist_id
LEFT JOIN Musical_genre mg ON
a.musical_genre_id = mg.musical_genre_id
AND mg.musical_genre = 'Rock'
--use musical_genre_id = 201 if you like, but then you could remove the last left join entirely.
LEFT JOIN Song s ON
a.album_id = s.album_id
GROUP BY
mg.musical_genre_id,
mg.musical_genre,
ra.artist_name
ORDER BY
nr_rocksongs ASC

Left join pre-filtering on first table in postgres

I want to run a query to get user photo album ids, names, and picture count in the album. This query works:
SELECT album.id, album.name, count(pictures.*)
FROM album
LEFT JOIN pictures
ON (pictures.album_id=album.id)
WHERE album.owner = ?
GROUP BY album.id;
I have tons of pictures, and lots of albums, but the join is running before filtering for the user I'm interested in.
I have seen other answers that filter inside the join based on the 2nd table's values, but I want to filter on album.owner which is not included in the 2nd table. How can I filter before the join? (and is it efficient? will I break indexes?)
For this query:
SELECT a.id, a.name, count(p.album_id)
FROM album a LEFT JOIN
pictures p
ON p.album_id = a.id
WHERE a.owner = ?
GROUP BY a.id;
You want an index on album(owner, id, name). This should speed your query.
However, it will probably be faster if phrased like this:
SELECT a.id, a.name,
(SELECT count(*)
FROM pictures p
WHERE p.album_id = a.id
)
FROM album a
WHERE a.owner = ?
Here you want the above index and an index on pictures(album_id).

Add if statement to Oracle query

I have a query that needs to return a single row if there are more than 2 rows with a certain ID. I figured the best way to do this was to add a counter in my query to count the instances of x and then return the results if x >=2 but I'm not sure how in Oracle.
My query now returns all of the instances of x in all playlists. I need it to return the playlist only if it has more than 2 instances of x
Select * from PLAYLIST p
left join PLAYLIST_SONGS ps on p.PLAYLIST_ID = ps.PLAYLIST_ID
join SONG s on ps.SONG_ID = s.SONG_ID
join Artists art on s.ARTIST_ID = art.ARTIST_ID
where art.BAND='x'
and p.NUM_SONGS >=2;
If you want to get the playlists with 2 or more songs of a certain artist, something like this might help you out:
SELECT *
FROM playlist p
WHERE (SELECT COUNT(1)
FROM playlist_songs ps JOIN song s ON ps.song_id = s.song_id
JOIN artists art ON s.artist_id = art.artist_id
WHERE ps.playlist_id = p.playlist_id
AND art.band = 'X') >= 2
Here's the concept of having and a group by to get songs with count > 1. Note field 1,2,3,4 in this case must not cause the records you want to combine to be unique. Otherwise, pablomatico's approach could work
Select Field1, Field2, Field3, Field4
from PLAYLIST p
left join PLAYLIST_SONGS ps on p.PLAYLIST_ID = ps.PLAYLIST_ID
join SONG s on ps.SONG_ID = s.SONG_ID
join Artists art on s.ARTIST_ID = art.ARTIST_ID
where art.BAND='x'
GROUP BY Field1, Field2, Field3, Field4
HAVING count(PS.Song_ID) >=2
You could also use an analytic function (window function) such as over partition by assign a row number to each song. something like row_number() over (partition by song_Id)
One other solution would be to use an inline correlated view to also get the number of songs:
select
p.*,
(
select
count(distinct s.song_id)
from
playlist_songs ps
join songs s on s.song_id = ps.song_id
join artists art on s.artist_id = art.artist_id
where p.playlist_id = ps.playlist_id
) number_of_songs
from
playlist p
where
number_of_songs > 1;