Reputation: 3755
I have the following SQL query:
SELECT
Customers.CustomerName AS FullName,
Customers.Id AS CustomerId,
Customers.UserRoleId AS UserRoleId,
Customers.Email AS Email,
IFNULL(Customers.StudentId, '') AS CustomersStudentId,
IFNULL(Customers.MagentoId, '') AS MagentoId,
Sections.Id AS SectionId,
Sections.SectionNumber AS SectionNumber,
Sections.SectionName AS SectionName,
Courses.Id AS CourseId,
IFNULL(Courses.CourseName, '') AS CourseName,
IFNULL(Courses.CourseNumber,'') AS CourseNumber,
IFNULL(Courses.CourseDepartment, '') AS CourseDepartment,
IFNULL(Courses.Notes, '') AS CourseNotes,
IFNULL(Courses.Year, '') AS CourseYear,
IFNULL(Courses.CourseType, '') AS CourseType,
StudentsCourses.Id AS StudentsCoursesId,
IFNULL(StudentsCourses.StudentId, '') AS StudentsCoursesStudentId,
IFNULL(SiteProfile.StudentIdField, '') AS StudentIdField,
IFNULL(SiteProfile.SchoolEmailDomain, '') AS SchoolEmailDomain,
IFNULL(Orders.Id, '') AS OrderId
FROM Customers
LEFT JOIN StudentsCourses ON Customers.Id = StudentsCourses.CustomerId
LEFT JOIN Sections ON StudentsCourses.SectionId = Sections.Id
LEFT JOIN Courses ON StudentsCourses.CourseId = Courses.Id
LEFT JOIN BooksCourses ON Courses.Id = BooksCourses.CourseId
LEFT JOIN Products ON BooksCourses.ISBN = Products.ISBN
LEFT JOIN EbookVendors ON Products.EbookVendorId = EbookVendors.Id
LEFT JOIN Orders ON Customers.Id = Orders.CustomerId
LEFT JOIN SiteProfile ON Courses.SchoolCode = SiteProfile.SchoolCode
WHERE Customers.Id <> 10
AND StudentsCourses.SectionId IS NOT NULL
AND StudentsCourses.Delete <> 2
AND Courses.SchoolCode = '{$criteria["school_code"]}'
AND Courses.Year = {$criteria["year"]}
AND Courses.CourseType LIKE '{$criteria["term"]}'
Records will always exist in the Customers
table. But sometimes there will be no associated records in any of the other joined tables.
How do I modify the query so that the additional SELECT
and WHERE
clauses don't break the results when there are only records in the Customers
table?
EDIT:
When the record only exists in Customers
, I want that record and I want the WHERE
clauses that don't pertain to the Customers
table to be ignored.
If the record exists in a joined table, I want the WHERE
clause that pertains to that joined table to work.
Upvotes: 1
Views: 1588
Reputation: 467
Both wrong. You can't have a query that returns two different shapes of tuples: these columns from here if this exists, but those columns from both here and there if hat exists. One query, one shape.
That having been sternly said, let's relax a little bit.
Just do an outer join, and if the data to be joined doesn't exist (= can't be found), NULL values will be silently, painlessly filled into the indicated columns. "Populated" is a fancier word for that.
Upvotes: 1
Reputation: 6202
When you left join, you're going to get NULLs in the fields for which there is no corresponding "right" record, so you have to account for that:
WHERE Customers.Id <> 10
-- AND StudentsCourses.SectionId IS NOT NULL
AND (StudentsCourses.Delete <> 2 OR StudentsCourses.Delete IS NULL)
AND (Courses.SchoolCode = '{$criteria["school_code"]}' OR Courses.SchoolCode IS NULL)
AND ( Courses.Year = {$criteria["year"]} OR Courses.Year IS NULL)
AND (Courses.CourseType LIKE '{$criteria["term"]}' OR Courses.CourseType IS NULL)
Upvotes: 1
Reputation: 70523
You need to change the where statement to deal with nulls. Like this
WHERE Customers.Id <> 10
-- AND StudentsCourses.SectionId IS NOT NULL
AND COALESCE(StudentsCourses.Delete,0) <> 2
AND COALESCE(Courses.SchoolCode,'{$criteria["school_code"]}') = '{$criteria["school_code"]}'
AND COALESCE(Courses.Year,{$criteria["year"]}) = {$criteria["year"]}
AND (Courses.CourseType is null or Courses.CourseType LIKE '{$criteria["term"]}')
When you left join and the value does not exist you will have null for those items -- to still see the row you need to not have your where statement filter out those items.
There is another way to do it which is to put the criteria in the joins. So for example course type would look like this:
LEFT JOIN Courses ON StudentsCourses.CourseId = Courses.Id and Courses.CourseType LIKE '{$criteria["term"]}'
If you do this then you don't need to add the filter to the where -- it will only be applied to the join and will return null for the table columns if the join does not exist.
Upvotes: 1