I have 4 tables, album, artist, song_cover and song.
Am trying to join the 3 tables to the album table and include the total number of songs within each album.
The query I have so far returns results as expected but takes almost over a minute to execute.
SELECT frco_album.*,
COUNT(frco_song.song_id) AS TotalSongs,
artist_aka, artist_address,
cover_filename
FROM frco_album
LEFT JOIN frco_song ON frco_album.album_id =
frco_song.song_album_id
LEFT JOIN frco_artist ON frco_album.album_artist =
frco_artist.artist_id
LEFT JOIN frco_song_cover ON frco_album.album_cover_id =
frco_song_cover.cover_id
GROUP BY frco_album.album_id
ORDER BY album_month DESC LIMIT 0, 20;
When I get rid of the song table LEFT JOIN song ON album.album_id = song.song_album_id and COUNT(song.song_id) AS TotalSongs, the query executes fast, as expected.
What am I doing wrong here?
EDIT: I've edited the question to include the tables and changed the query to reflect the actual rows in the tables.
The left join will multiply rows and then you condense them back using group by. Assuming that there is one artist and cover per album I would try counting the songs inside the select clause:
SELECT album.*, artist_aka, artist_address, cover_filename, (
SELECT COUNT(*)
FROM songs
WHERE song.song_album_id = album.album_id
) AS TotalSongs
FROM album
LEFT JOIN artist ON album.album_artist_id = artist.artist_id
LEFT JOIN song_cover ON album.album_cover_id = song_cover.cover_id
ORDER BY album_plays DESC
LIMIT 0, 20
Related
I have a query that fetches data from Six tables but it takes too much time to fetch data.The browser loads and shows sometimes nothing as a result.When I run this query in the MySQL database, it takes a long time to execute.
SELECT SQL_CALC_FOUND_ROWS movies.*,
curriculums.name AS curriculum,
teachers.name AS teacher,
movie_sub_categories.name AS sub_cat_name,
movie_categories.name AS cat_name
FROM movies
LEFT JOIN curriculums on movies.curriculum_id = curriculums.id
LEFT JOIN teachers on movies.teacher_id = teachers.id
LEFT JOIN movies_movie_sub_categories on movies.id = movies_movie_sub_categories.movie_id
LEFT JOIN movie_sub_categories on movies_movie_sub_categories.movie_sub_category_id = movie_sub_categories.id
LEFT JOIN movie_categories on movie_sub_categories.movie_category_id = movie_categories.id
ORDER BY id LIMIT 0, 50
Here all of my table structure
That's not a very exciting query -- it simply delivers the first 50 rows of whichever table id belongs to. When JOINing, please qualify columns so we know what is going on.
Do you really need LEFT?
Assuming you need LEFT and id belongs to movies, then this should run a lot faster:
Meanwhile, find how many rows there are in movies only once, so you don't have to compute it every time.
SELECT movies.*, curriculums.name AS curriculum,
teachers.name AS teacher, movie_sub_categories.name AS sub_cat_name,
movie_categories.name AS cat_name
FROM ( SELECT id FROM movies ORDER BY id LIMIT 0, 50 ) AS m
JOIN movies USING(id)
LEFT JOIN curriculums AS c ON movies.curriculum_id = c.id
LEFT JOIN teachers AS t ON movies.teacher_id = t.id
LEFT JOIN movies_movie_sub_categories AS mmsc ON movies.id = mmsc.movie_id
LEFT JOIN movie_sub_categories AS msc ON mmsc.movie_sub_category_id = msc.id
LEFT JOIN movie_categories AS mc ON msc.movie_category_id = mc.id
ORDER BY m.id
Please use SHOW CREATE TABLE; we need to see if you have sufficient indexes, such as
mmsc: INDEX(movie_id)
the table movies_movie_sub_categories needs to have an index on movie_id and a separate index on movie_sub_category_id. Without those two indexes the query builder will be forced to scan every record twice (since the query has two separate join clauses that reference that table)
I'm trying to get a list of all the bands in the database a long with the number of songs and albums associated with each band. The song table is ~18,000 lines, the album table is ~3,000 lines, and the bands table is ~1,200 lines. I have indexes on BandID in both the albums and songs tables, but this query still takes about 26 seconds to run! Is there a better/faster way to get all of this information in one query?
SET SQL_BIG_SELECTS=1;
SELECT b.ID, b.Name, b.URL, b.Alpha, b.Sort, b.Image, b.Path, COUNT(DISTINCT s.ID) AS SongCount, COUNT(DISTINCT a.ID) AS AlbumCount FROM mft_bands AS b
LEFT JOIN mft_albums AS a ON a.BandID = b.ID
LEFT JOIN mft_songs AS s ON s.BandID = b.ID
WHERE b.Enabled=1 GROUP BY b.ID ORDER BY b.Name
So I have this table of albums and images. Images have a column named album_id which takes the album ID they are sitting on. So far so good.
Now I'm in need to select information from the Albums table and I also need the count of images for each album row. I tried using a LEFT JOIN and a COUNT(*), but it would return only one row, which is highly inefficient for my case.
This is the original query I'm using which wont return anything count related:
SELECT album_id, album_name, album_preview, album_owner, album_time, album_access
FROM imgzer_albums WHERE album_owner = SOME_VALUE
And this is the query with the LEFT JOIN:
SELECT a.album_id, a.album_name, a.album_preview, a.album_owner, a.album_time, a.album_access, COUNT(i.*) AS images
FROM imgzer_albums a
LEFT JOIN imgzer_images i
ON a.album_id = i.album_id
WHERE album_owner = SOME_VALUE
How do I get the images count for each corresponding album ID without being limited to one result only?
Try This
SELECT a.album_id, a.album_name, a.album_preview, a.album_owner, a.album_time, a.album_access, COUNT(i.*) AS images
FROM imgzer_albums a
LEFT JOIN imgzer_images i
ON a.album_id = i.album_id
WHERE album_owner = SOME_VALUE
GROUP BY a.album_id
a solution without grouping is a correlated query:
SELECT a.album_id, a.album_name, a.album_preview, a.album_owner, a.album_time, a.album_access,
(select COUNT(*) from imgzer_images i where a.album_id = i.album_id) AS images
FROM imgzer_albums a
WHERE album_owner = SOME_VALUE
I'm trying to get data from three tables (photos, albums, album_photos),
then the program searches a user's albums in the album table, then look for every album the ID's of the photos in album_photos, and then, for each ID, look at the photos table all data by ID.
Yesterday I asked something like this: Inner join with 3 tables, but now, I think the question is different, I'm wondering how I can add a limit to a request by inner join.
So, I'm working now in this code:
SELECT a.album_name, a.album_id, c.*
FROM albums a
INNER JOIN album_photos b ON a.album_id = b.album_id
INNER JOIN photos c ON b.photo_id = c.photo_id
WHERE (
SELECT COUNT(*)
FROM album_photos d
WHERE b.album_id = d.album_id
AND d.nick = :nick
) <=5
Ok, this code select's the albums that have 5 or less photos. I do not want the code to do that, no matter how many photos have the album, I want to show the album with a LIMIT OF 5 photos.
Other people have told me that you can not do it, I believe that this is not so, because the SQL language is very complex and I think we should have the tool to do it.
Is there any way to do this in a proper way?
*In the link that I'm shared above I put an example about the output data.
Try changing the where clause to this:
WHERE (
SELECT COUNT(*)
FROM album_photos d
WHERE d.album_id = b.album_id and
d.photo_id <= b.photo_id
AND d.nick = :nick
) <= 5
This counts the number of photos in order, not just the number of photos in the album.
Since album_photos has a mapping relationship between photos and albumns, you can specify the number of photos to join on by using TOP:
SELECT a.album_name, a.album_id, p.*
FROM albums a
INNER JOIN album_photos ap ON
ap.photo_id = (select top 5 photo_id from album_photos where a.album_id = ap.album_id order by photo_id)
INNER JOIN photos p ON ap.photo_id = p.photo_id
The Order by photo_id in the subquery will ensure the same 5 (or fewer) photos are returned
EDIT PER COMMENT. Modifying to use MySql LIMIT instead of T-SQL TOP
SELECT a.album_name, a.album_id, p.*
FROM albums a
INNER JOIN album_photos ap ON
ap.photo_id = (select photo_id from album_photos where a.album_id = ap.album_id order by photo_id LIMIT 0, 5)
INNER JOIN photos p ON ap.photo_id = p.photo_id
I have movie database that has these tables: new_movies, ratings, critic_ratings, colors
I'm trying to execute this SELECT statement which will combine these 4 tables on the same movie using 'mid' (movie id):
SELECT DISTINCT
new_movies.*,
movies_db.*,
ratings.rating,
ratings.count,color,
critic_ratings.rating AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON
new_movies.mid = movies_db.mid
LEFT JOIN
ratings
ON
new_movies.mid = ratings.mid
LEFT JOIN
colors
ON
new_movies.mid = colors.mid
LEFT JOIN
critic_ratings
ON
new_movies.mid = critic_ratings.mid
ORDER BY
title ASC
But I get this error:
The SELECT would examine more than
MAX_JOIN_SIZE rows; check your WHERE
and use SET SQL_BIG_SELECTS=1 or SET
SQL_MAX_JOIN_SIZE=# if the SELECT is
okay
How do I properly do this query?
If you don't want to enable big selects, you could reform this using correlated sub-queries. (I don't know if you'll still hit the limit or not though.)
SELECT DISTINCT
new_movies.*,
movies_db.*,
(SELECT rating FROM ratings WHERE new_movies.mid = ratings.mid) AS rating,
(SELECT count FROM ratings WHERE new_movies.mid = ratings.mid) AS rating_count,
(SELECT color FROM colors WHERE new_movies.mid = colors.mid) AS colour,
(SELECT rating FROM critic_ratings WHERE new_movies.mid = critic_ratings.mid) AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON new_movies.mid = movies_db.mid
ORDER BY
title ASC
Also, worth a test to see if the LEFT JOINs are actually the cause, can you execute the following?
SELECT DISTINCT
new_movies.*,
movies_db.*
FROM
new_movies
INNER JOIN
movies_db
ON new_movies.mid = movies_db.mid
ORDER BY
title ASC
why do you have a movies and a new_movies table? surely a release date field would be sufficient for that - would cut out a join too...
to that end I would create a view of that data and query that instead.
But back to your query:
SELECT DISTINCT
new_movies.*,
movies_db.*,
ratings.rating,
ratings.count,
color,
critic_ratings.rating AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON
new_movies.mid = movies_db.mid
LEFT JOIN
ratings
ON
new_movies.mid = ratings.mid
LEFT JOIN
colors
ON
new_movies.mid = colors.mid
LEFT JOIN
critic_ratings
ON
new_movies.mid = critic_ratings.mid
ORDER BY
title ASC
I can't see anything obvious... perhaps you can post the results of an explain query?
There is no problem with your query per se. It's just that you're selecting all movies (no WHERE, no LIMIT) and since you're joining ratings for e.g., it will join all ratings to each movie. You are just reaching the max amount of data allowed for joins.
I'm not sure why you'd need to select all movies. Perhaps you can use a limit. Otherwise you can just try the solutions in the error message.