Search by foreign key - php

I’m working on an application that allows users to search for music, artists, albums and mixtapes.
The DB has these four tables: Music, Artists, Mixtapes, Albums.
The 3 tables; mixtapes, music and albums are related to the artist using foreign keys in a column called artist_id.
It is quite easy to get search results from each of the three tables by using a query such as this:
$music = "SELECT * FROM music WHERE song_title LIKE '%$search_term%'";
However, I’m finding it a bit daunting to get results for albums, mixtapes and music where artist_name = search term since the artist’s reference is not made by name but rather by artist_id
How can I return results for music, albums and mixtapes for a user supplied search term (ie. artist)?

You can achieve this by using an inner join
"SELECT * FROM music INNER JOIN artist ON music.artist_id = artist.id WHERE artist.name LIKE '%$search_term%'";

You need to use a join between the tables, something like this:
select * from music m
inner join artists a on (m.artist_id = a.artist_id)
where a.artist name like ....

Related

How to retrieve tables from database tables based on 1s and 0s?

I have 2 tables at the moment: Artists and Genres.
Genres are connected to artists using artist_id. The phpmyadmin genres table is set up as follows:
1s indicates that the artist with id=3, has selected classical and rap using a checkbox.
I would like to efficiently display a card, which will display the artist genres in a list. For every 1 in the row where artist_id = $id , output all genres ( in our case, classical and rap).
I was thinking about creating a new object called artistgenre, and using new artistgenre(); to create a new object and assign attributes. Maybe I don't even need to do that. Currently I have an object called artist, and I create $artist = Artist::findbyid($sessionid); and use $artist->name; $artist->location; to output data from the database.
I think this query is what you need:
SELECT g.id, g.name
FROM artists a
INNER JOIN artist_genres ag ON a.id = ag.artist_id
INNER JOIN genres g ON ag.genre_id = g.id

Select items where ID present in another column MySQL

I have a table of albums, each album has an ID.
I also have a table of reviews, each review is linked to a corresponding album through the column albumID.
I'm wondering how I can select all albums who's ID's are present in the reviews table.
I was thinking of selecting all albumId's from the reviews column then doing a select where id in but I feel like this would be horribly inefficient.
This is in MySQL
Albums Table
- ID
Reviews Table
- ID
- albumID
Desired result: All albums who have a review. (eg: All albums that have their ID present in the Reviews table)
Here's one approach using a simple JOIN. The inner join notation will only include records that exist in both tables. It allows you to access data in both tables which may be useful if you need data out of reviews too.
Select * from albums A
inner join reviews R
on A.ID = R.AlbumID
This next approach is generally the fastest but you can only get data from albums. This uses what's known as a correlated sub query and is generally the fastest approach.
SELECT * from albums A
where exists (Select 1 from reviews R where A.ID = R.albumID)
and a third approach but generally the slowest... uses a concept called IN(). The sub query here generates a list of ID's from reviews and only shows albums in that list.
Select * from albums where ID IN (SELECT albumID from Reviews)
This would work:
select a.* from albums as a
inner join reviews as r
on r.albumID = a.ID

How to implement search for a tagging system?

Many types of systems use tags to organize content, including blogs and StackOverflow. Let's say I'm making a movies website and want users to be able to tag movies, as well as search for movies using combinations of tags.
Here's a sample database structure:
movies:
id, name
movie_tag_options (used to provide users with list of available tag options):
id, name
movie_tags:
id, m_id, mto_id
Let's say there's a movie called "Transformers 9 - Explosions" and it has the tags "action", "PG-13", and "terrible movie". I want users to be able to find this movie by performing a search for "action,PG-13,terrible movie".
I will explode the string of tags in PHP to get an array of tags:
action
PG-13
terrible movie
So my question is, how do I use the tag names to find movies with these tags? The movies can have other tags as well, but should only be returned if they have all of the tags in the search.
The only solution I can think of is to denormalize the tag name and to store it in movie_tags as well as movie_tag_options (i.e. adding a duplicate name column to movie_tags), then constructing a query in PHP that generates JOIN statements for each tag. Something like this:
SELECT id, name FROM movies
JOIN movie_tags mt0 ON mt0.name = "action"
JOIN movie_tags mt1 ON mt1.name = "PG-13"
JOIN movie_tags mt2 ON mt2.name = "terrible movie"
The JOIN lines would be generated via PHP and inserted into the query.
The downside to this approach is storing the tag names in two tables instead of one.
Is there a better way?
or you can use
select a.name, count(c.id) c
from movies a
join movie_tags b on a.id = b.m_id
join movie_tag_options c on b.mto_id = c.id
where c.name in ('action', 'PG-13', 'terrible movie')
group by a.id
having c = 3;

determine SQL query of albums, and total videos

For the query i need to do, a user uploads videos onto an album, on their video page, it has the list of albums, and the total of videos below it.
Currently, what i am trying to do is a union, however this is not working, this is my code:
$query="SELECT albname, albcover, lid, NULL as vidcount FROM albums WHERE USERID='".mysql_real_escape_string($USERID)."' and verified='1'
UNION
SELECT NULL as albname, NULL as albcover, NULL as lid, count(*) as vidcount FROM albs_vids A LEFT JOIN albums B USING(ALBID) WHERE B.USERID='".mysql_real_escape_string($UID)."'";
So, what happens is the SQL query needs to find the data of the album, ie albname, albcover and lid from the table albums. Then find the amount of videos in the table albs_vids which correspond to the album. The album is specified by ALBID in both tables.
Hard to completely understand what you're asking ,but this will give you the count of videos for each album that has your userid:
$sql = "SELECT a.albname, a.albcover, a.lid, COUNT(*) AS vidcount
FROM albums AS a
LEFT JOIN albs_vids AS b ON b.albid = a.albid
WHERE b.userid='".mysql_real_escape_string($UID)."'
GROUP BY a.albname";

mysql many-to-many query issue

i have many to many database and i'm there is a query that i just got stuck with and cant do it.
i have 4 tables Artists, Tracks, Albums, Clips
now i'm on the artist page so i need to get them by the artist page, i already got all of them, but not the way i want them.
because some tracks, albums, clips belong to other artists as well (duet) and i need to display their name.
but the problem is that i'm selecting using the artist id so my GROUPC_CONCAT function wont work here is the query that gets the artist albums.
SELECT al.album_name, GROUP_CONCAT(a.artist_name SEPARATOR ', ') AS 'artist_name'
FROM
Albums al
LEFT JOIN
ArtistAlbums art ON art.album_id = al.album_id
LEFT JOIN
Artists a on a.artist_id = art.artist_id
WHERE
a.artist_id = 10
GROUP BY
al.album_id
one of the albums have two artists attached to it, but it does not get the other artist name.
when i select by the album_id i get the two artists.
please note that i'm new to mysql and i did not find any answers on this particular problem almost no resources on many-to-many querying.
how can i tackle this problem.?
any resources or books on many-to-many that show how to deal with the database on the application layer will be much appreciated,
thanks in advance.
Think of table aliases as really being row aliases. That is, for purposes of expressions in the WHERE clause and the select-list, the alias refers to a single row at a time.
Since you've created a condition such that a.artist_id = 10, then only rows for that artist match the condition. What you really want is to match all artists on an album given that one artist is artist_id = 10.
For that, you need another join, so that the row where artist_id = 10 is matched to all the rows for that respective album.
SELECT al.album_name, GROUP_CONCAT(a2.artist_name SEPARATOR ', ') AS `artist_name`
FROM
Albums al
INNER JOIN
ArtistAlbums art ON art.album_id = al.album_id
INNER JOIN
Artists a on a.artist_id = art.artist_id
INNER JOIN
ArtistAlbums art2 ON art2.album_id = al.album_id
INNER JOIN
Artists a2 on a2.artist_id = art2.artist_id
WHERE
a.artist_id = 10
GROUP BY
al.album_id
P.S.: I've also replaced your use of LEFT JOIN with INNER JOIN. There's no reason you needed LEFT JOIN, since you're explicitly looking for albums that have a matching artist, not all albums whether or not it has artist 10. Review the meaning of different types of join.
Re your followup question:
I don't know of a book specifically about many-to-many queries. I'd recommend books like:
SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming, which is my own book and it does cover many-to-many tables.
SQL and Relational Theory to understand joins better.
Joe Celko's SQL Programming Style, which imho is Joe Celko's best book.

Categories