MYSQL query through many layers of one to many relationships - mysql

How do I select all things from the many of a one to many relationship, several layers down in many one-to-many relationships? I'm not sure how to nest all those left joins.
Example
There are many Institutions
Each Institution has many Departments
Each Department has many Forums
Each Forum has many Users
Each User has many Posts
Each Post has many Comments
Find all Comments for an Institution.
I googled around, but I'm not sure what the name for this is - chain nested one to many relationship queries? The closest I found was SQL left join vs multiple tables on FROM line?

Without knowing your schema and making some assumptions:
SELECT c.*
FROM
Institution i
INNER JOIN Department d ON d.InstitutionID = i.InstitutionID
INNER JOIN Forums f ON f.DepartmentID = d.DepartmentID
INNER JOIN `User` u ON u.ForumID = f.ForumID
INNER JOIN Post p ON p.UserID = u.UserID
INNER JOIN Comment c ON c.PostID = p.PostID
WHERE
i.InstitutionID = 42

Related

to get different columns from single query

Consider the data about projects and members stored in tables below.

Projects(id, title)
Members(id, name, project_id)

Generate a report to list all the projects, members working on them. Also list the projects that do not have any employees assigned yet and also the employees who are available as free resources.
Table-
Projects(id, title)
Members(id, name, project_id)
can someone optimize the query as i applied outer join and i got all answers together.i need to separate the columns as per required question.
Select p.title, m.id
From projects p FULL OUTER JOIN
Members m
where p.id = m.project_id;
MySQL does not support full join. So do this in two steps:
Select p.title, m.id
From projects p LEFT JOIN
Members m
ON p.id = m.project_id
union all
select null, m.id
from members m
where not exists (select 1 from projects p where p.id = m.project_id);

Redmine: What is the sql relationship between projects and contacts (companies)

I have a hard time figuring out the SQL relationship between the companies from the contacts table (where is_company=1) and projects.
The following query works for 95% of the time, but I came to the conclusion that the contacts.first_name is not the relationship to the projects table:
SELECT p.id, p.name FROM custom_values
INNER JOIN custom_fields c ON c.id = custom_values.custom_field_id
INNER JOIN projects p ON p.id = customized_id
WHERE custom_values.value LIKE '%{CONTACT_FIRST_NAME}%'
Please help.

Is it possible to join many to many and one to many in one go?

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.

MySQL added the date to a many to many table?

I have three tables, the first two are used to store information about people.
So how do I add the date to the link the 3 tables?
Trying to practice my school work at home and have no idea how to do this!
Edit: all I can think off would be this SELECT B.Date_of_exams, C.last_name, B.subjects_name
If I understand what you want, you need to join the tables using INNER JOIN like this:
SELECT B.Date_of_exams, C.last_name, B.subjects_name
FROM
entries A
INNER JOIN subjects B
ON A.subjects = B.subjects_id
INNER JOIN students C
ON A.student = C.student_id

How to best do a SQL left join null check where all must be null?

Suppose I have table Person, who owns many Books, which cover many Subjects.
A Book might not yet have any Subjects assigned to them.
It's easy to query for Persons who own SOME Books that have no Subjects with a left join and a null check. e.g.:
select * from persons p
inner join person_book pb on pb.person_id = p.id
left join book_subject bs on bs.book_id = person_book.book_id
where book_subject.book_id is null;
What is the best way to query for a Person who ONLY owns books with no established subjects?
I know I can find people with books, and people with at least 1 book with subjects, then find the difference. But is there a direct way?
(This would be in MySQL if it makes a difference).
Try:
select p.*
from persons p
inner join person_book pb on pb.person_id = p.id
left join book_subject bs on bs.book_id = person_book.book_id
group by p.id
having count(bs.book_id) = 0