I need to display a table that lists a game's title, developer(s) and publisher(s). Each game can have multiple developers and publishers. From the below diagram, is it possible to get all this information through one query using inner joins or will I have to make multiple database transactions?
As it stands I have been able to obtain a game's developer (singular) but I'm not sure how to grab multiple developers as well as multiple publishers in the one query. This is my query so far:
SELECT games.id, games.title, companies.id, companies.name
INNER JOIN game_developer ON game_developer.games_id = games.id
INNER JOIN companies ON companies.id = game_developer.companies_id
GROUP BY games.title
ORDER BY games.title
LIMIT 50
The final product should look something like this:
Use GROUP_CONCAT to get all the names:
SELECT games.id, games.title,
GROUP_CONCAT(DISTINCT dc.name) AS developers,
GROUP_CONCAT(DISTINCT pc.name) AS publishers
INNER JOIN game_developer ON game_developer.games_id = games.id
INNER JOIN companies AS dc ON dc.id = game_developer.companies_id
INNER JOIN game_publisher AS gp ON gp.games_id = games.id
INNER JOIN companies AS dp ON dp.id = gp.companies_id
GROUP BY games.id
ORDER BY games.title
LIMIT 50
You need to use DISTINCT because joining with both publishers and developers will generate a cross product with lots of duplicates.
Related
I have 4 tables, three are many to many relationship:
Student(StudID,GroupId,Name,....)
Lesson(LessID,LessonName,Mark)
StudentLesson(StudID,LessID)
and the relationship between student and Group is One to Many
Student(StudID,Name,....)
Group(GroupId,GroupNumber)
What I want is how select Name, LessonName, Mark, GroupNumber
select S.Name, L.LessonName, L.Mark, G.GroupNumber from Student s
join StudentLesson SL on SL.StudId = S.StudId
join Lesson L on SL.LessID = L.LessID
Join Group G on G.GroupId = S.GroupId
I think the error in this line Join Group G on G.GroupId=S.GroupId, because when I omit it, it works between many to many but between one to many it didn't work.
group is a reserved word, so it needs to be quoted. In MySQL, you can use backticks:
select S.Name, L.LessonName, L.Mark, G.GroupNumber
from Student S
join StudentLesson SL on SL.StudId = S.StudId
join Lesson L on SL.LessID = L.LessID
Join `Group` G on G.GroupId = S.GroupId
Based on Comments: the query is fine; you lack data that matches the results you're after.
There are no students with a groupID
There are no students with a groupID matching GROUPID in the group table.
To prove this out you could simply make the last join a LEFT Join provided you have no where clause with limits on Group.
FROM:
select S.Name,L.LessonName,L.Mark,G.GroupNumber from Student s
join StudentLesson SL on SL.StudId=S.StudId
join Lesson L on SL.LessID =L.LessID
Join Group G on G.GroupId=S.GroupId
TO:
SELECT S.Name, L.LessonName, L.Mark, G.GroupNumber
FROM Student s
INNER JOIN StudentLesson SL on SL.StudId=S.StudId
INNER JOIN Lesson L on SL.LessID =L.LessID
LEFT JOIN Group G on G.GroupId=S.GroupId
This will show you all students w/ lessons and groupNumber if the groupID's match; but i'm betting they will all be NULL.
So are you after all students regardless if they have lessons or groups if so your inner joins should be left. If you're only after students that have lessons and belong to groups then they all need to be inner joins. Just depends on what you're after!
Left join will say include all records from the prior data joins, and only those that match from this join (to group in the example)
My tables have the following schema:
wp_careers
wp_locations
wp_careers_locations
wp_educations
A career applicant can apply to many locations, and have many educational records.
The desired result is to get ALL records from wp_careers and group the applied locations as a locations fields, and put all educational records (wp_educations) as an array attached to the applicant.
Right now I know how to join many to many relations and group the locations:
SELECT c.*, GROUP_CONCAT(l.name) as locations
FROM wp_careers c
JOIN wp_careers_locations cl ON c.id = cl.career_id
JOIN wp_locations l ON cl.location_id = l.id
GROUP BY c.id
But I don't know how to extend this query to include the educational records.
One way would be to just join again:
SELECT c.*, GROUP_CONCAT(DISTINCT l.name) as locations,
GROUP_CONCAT(DISTINCT e.institute) AS edu_institutes
FROM wp_careers c
LEFT JOIN wp_careers_locations cl ON c.id = cl.career_id
LEFT JOIN wp_locations l ON cl.location_id = l.id
LEFT JOIN wp_educations e ON c.id = e.career_id
GROUP BY c.id
But this is likely to create a Cartesian product, as it will inadvertently join every location to every education. So if you have three locations and two educations for a given career, it will generate 3x2 = 6 rows when you didn't expect it to. I tried to compensate for this with DISTINCT so the list of names in each GROUP_CONCAT() will eliminate duplicates.
But honestly, I would prefer to run two queries. One for locations, and a second query for educations. That would avoid the Cartesian product. MySQL is not so weak that it can't handle an extra query, and it might actually be less expensive than doing the DISTINCT operations.
Re your comment:
You want to restrict careers in the education query only to those that have at least one location?
You can do this with a semi-join:
SELECT c.*, GROUP_CONCAT(e.institute) AS edu_institutes
FROM wp_careers c
JOIN wp_educations e ON c.id = e.career_id
WHERE c.id IN (SELECT career_id FROM wp_career_locations)
GROUP BY c.id
Even though there may be multiple rows in wp_career_locations matching each respective c.id, it doesn't cause a Cartesian product.
I have the following tables in my database.I only listed the important columns which can be used for joining.
I need to get the following output
Currently I'm using two seperate queries for each COUNT value
For assigned licenses
select
products.id,products.name,COUNT(assigned_licenses.id)
from
deployment_users
inner join
assigned_licenses
on
deployment_users.id = assigned_licenses.deployment_user_id
inner join
products
on
assigned_licenses.id = products.id
and
deployment_users.customer_id = 10
group by
assigned_licenses.id
;
For total licenses
select
products.id,products.name,COUNT(total_licenses.id)
from
customers
inner join
total_licenses
on
customers.iccode = licenses.iccode
inner join
products
on
total_licenses.id = products.id
and
customers.id = 10
group by
total_licenses.id
;
Since there are more than a 1,000 products that need to be listed,I want to combine them into a single query.How can I do that?
Your specification leaves some room for interpretation (e.g. can a user have assigned licenses without total licenses? if yes my query will fail.) but I would go with this.
SELECT
products.id,
products.name,
Count(Distinct total_licenses.id) As CountTotalLicenses,
Count(Distinct assigned_liceses.deployment_users_id) As CountAssignedLicenses
FROM products
LEFT JOIN total_licenses ON total_licenses.products_id = products.id
LEFT JOIN customers ON customers.iccode = total_licenses.customers_iccode
LEFT JOIN assigned_licenses ON assigned_liceses.total_licenses_id = total_licenses.id
WHERE
customers.id = 10
GROUP BY
products.id,
products.name
For the future it would be awesome if you could paste code as code and not as an image. People cannot simple copy paste snippets of your code and have to type everything again...
Try joining Both of your query
SELECT * FROM (
(First Query) as assigned_licn
INNER JOIN
(Second Query) as total_licn
USING (id)
);
A user has a student (one to one) and a student can have many languages and hobbies (both times many to many).
If I run this query,
SELECT email, hobbies.name, languages.name
FROM users
INNER JOIN students
ON users.id = students.user_id
LEFT OUTER JOIN languages_student
ON students.id = languages_student.student_id
INNER JOIN languages
ON languages_student.language_id = languages.id
LEFT OUTER JOIN hobbies_student
on students.id = hobbies_student.student_id
INNER JOIN hobbies
ON hobbies_student.hobbie_id = hobbies.id
WHERE users.id = 6
I get this result set:
If I add another language to a student, I get six rows in the result set. Is there a way of combining the second and third columns in order to get something more compact and not redundant? Can each hobby appear just once and get a NULL in languages when they run out?
There are a couple of approaches to being able to aggregate this information. One is to do this in your application logic based on the type of result set you currently show. This might be done be reading the rows from the result set into an appropriate data structure you can then use in your application to display this information.
The second approach is to use GROUP_CONCAT() to concatenate values within same group (in this case email name) into a single row. That might lead to a results set like this:
shields.katlynn#swaniaski.biz Endurance Sports,Golf Balochi,Assamesse
This might mean that in your application, you would need to split apart the data in each row to get to individual values.
An example of how you might write the query to get the above result would be:
SELECT
email,
GROUP_CONCAT(DISTINCT hobbies.name) AS hobbies,
GROUP_CONCAT(DISTINCT languages.name) AS languages
FROM users
INNER JOIN students
ON users.id = students.user_id
LEFT OUTER JOIN languages_student
ON students.id = languages_student.student_id
INNER JOIN languages
ON languages_student.language_id = languages.id
LEFT OUTER JOIN hobbies_student
on students.id = hobbies_student.student_id
INNER JOIN hobbies
ON hobbies_student.hobbie_id = hobbies.id
WHERE users.id = 6
GROUP BY email
In either case, you will need some sort of post-retrieval data processing in your application.
i can write the specific query for that table and its relation, but merging them into one is the difficulty i'm having with
select clients, count(*)
from clients
inner join themes
on clients.id = themes.client_id
group by clients
select themes.id
from themes
inner join videos
on videos.theme_id = themes.id
select distinct videos.user_id,
from videos
inner join properties
on properties.user_id = videos.user_id
group by properties.user_id
basically, i want to count the amount of unique users for a client
the relationship is
a client has many themes
a theme has many videos
a video has one property
a user has many properties
thanks
Count the amount of unique users for a client:
select clients, count(DISTINCT properties.user_id) as num_users
from clients
inner join themes on clients.id = themes.client_id
inner join videos on videos.theme_id = themes.id
inner join properties on properties.user_id = videos.user_id
group by clients.clients_id;
You also might be able to get away with a bit shorter query:
Users always have properties (that is the assumption), then users with a video will be present in the property table and that then does not have to be joined:
select clients, count(DISTINCT videos.user_id) as num_users
from clients
inner join themes on clients.id = themes.client_id
inner join videos on videos.theme_id = themes.id
group by clients.clients_id;