Mysql Query Optimization - Shared Query need to optimized - mysql

Please help me to optimize below Query -
SELECT DISTINCT
al.displayName AS 'Brand',
al.locationName AS 'Campus',
pg.groupName AS 'School Phase',
result.programName AS 'Grade',
pc.categoryName AS 'Grade Category',
result.batchName AS 'Intake',
result.periodName AS 'Period',
admission.id AS 'ADmission',
result.stdName AS 'Student Name',
usr.code AS 'Student Id',
result.courseName AS 'Subject',
result.courseVariant AS 'Subject Variant',
cc.categoryName AS 'Subject Category',
fac.printName AS 'Teacher',
result.planPrintName AS 'Scheme',
planRank.marksObtainedFrom AS 'Maximum Marks',
planRank.gradeObtainedFrom AS 'Maximum Grade',
planRank.obtainedMarks AS 'Subject Level Marks',
planRank.grade AS 'Subject Grade',
planRank.obtainedMarks AS 'Percentage',
planRank.status AS 'Result Status',
result.levelOnePrintName AS 'Type',
typeRank.effectiveMarks AS 'Type Marks',
typeRank.grade AS 'Type Grade',
typeRank.status AS 'Type Result Status',
result.levelTwoPrintName AS 'Sub Type',
subTypeRank.effectiveMarks AS 'Sub Type Marks',
subTypeRank.grade AS 'Sub Type Grade',
subTypeRank.status AS 'Sub Type Result Status',
result.levelThreePrintName AS 'Method',
result.effectiveMarks AS 'Method Marks',
result.grade AS 'Method Grade',
result.status AS 'Method Result Status',
CASE
WHEN evntDetail.eventName IS NULL THEN evnt.detailSequenceNumber
WHEN evntDetail.eventName IS NOT NULL THEN evntDetail.eventName
ELSE NULL
END AS 'Event',
eventMarks.effectiveMarks AS 'Event Marks',
eventMarks.finalGrade AS 'Event Grade'
FROM
marksheet AS result
INNER JOIN
admission AS admission ON admission.id = result.admissionId
INNER JOIN
users AS usr ON usr.id = result.studentId
INNER JOIN
academy_location AS al ON al.id = admission.academyLocationId
INNER JOIN
programs AS prgm ON prgm.id = result.programId
LEFT OUTER JOIN
program_group AS pg ON pg.id = prgm.programGroupId
LEFT OUTER JOIN
program_category AS pc ON pc.id = prgm.programCategoryId
LEFT OUTER JOIN
courses AS course ON course.id = result.courseId
LEFT OUTER JOIN
course_category AS cc ON cc.id = course.courseCategoryId
LEFT OUTER JOIN
program_batch_course_param AS param ON result.courseVariantId = param.courseVarientId
AND result.periodId = param.progBatchPeriodConfigId
LEFT OUTER JOIN
prog_batch_course_faculty AS pbcf ON pbcf.progBatchCourseParamId = param.id
LEFT OUTER JOIN
users AS fac ON fac.id = pbcf.facultyId
LEFT OUTER JOIN
evaluation_plan_rank AS planRank ON result.admissionId = planRank.admissionId
AND (result.courseVariantId = planRank.courseVariantId
OR planRank.courseVariantId IS NULL)
AND result.sectionId = planRank.sectionId
AND result.periodId = planRank.periodId
AND result.evaluationPlanId = planRank.evaluationPlanId
LEFT OUTER JOIN
evaluation_plan_level_one_rank AS typeRank ON result.admissionId = typeRank.admissionId
AND (result.courseVariantId = typeRank.courseVariantId
OR typeRank.courseVariantId IS NULL)
AND result.periodId = typeRank.periodId
AND result.sectionId = typeRank.sectionId
AND result.evaluationPlanLevelOneId = typeRank.evaluationPlanLevelOneId
LEFT OUTER JOIN
evaluation_plan_level_two_rank AS subTypeRank ON result.admissionId = subTypeRank.admissionId
AND (result.courseVariantId = subTypeRank.courseVariantId)
AND result.periodId = subTypeRank.periodId
AND result.sectionId = subTypeRank.sectionId
AND result.evaluationPlanLevelTwoId = subTypeRank.evaluationPlanLevelTwoId
INNER JOIN
eval_seq_detail AS evnt ON result.evaluationPlanThreeId = evnt.evalSequenceId
LEFT OUTER JOIN
examination_result AS eventMarks ON result.admissionId = eventMarks.admissionId
AND (result.courseVariantId = eventMarks.courseVariantId
OR eventMarks.courseVariantId IS NULL)
AND result.sectionId = eventMarks.sectionId
AND result.periodId = eventMarks.periodId
AND evnt.id = eventMarks.evaluationDetailSequenceId
LEFT OUTER JOIN
evaluation_type_course typeCourse ON eventMarks.courseVariantId = typeCourse.courseVariantId
AND eventMarks.periodId = typeCourse.periodId
LEFT OUTER JOIN
exam_event_detail evntDetail ON eventMarks.evaluationDetailSequenceId = evntDetail.eventId
AND evntDetail.evaluationTypeCourseId = typeCourse.id
WHERE
eventMarks.examResultStatus IS NOT NULL
AND result.evaluationPlanId IS NOT NULL
AND result.evaluationPlanLevelOneId IS NOT NULL
AND result.evaluationPlanLevelTwoId IS NOT NULL
AND result.evaluationPlanThreeId IS NOT NULL;
In tables marksheet = '740119' and examination_result = '4891575' approx records.
when I execute query then it will take around 10 min and also show time out error, as data-set is large.
I applied indexes on table's for performance but still Query take lots of time.
I applied Explain on Query to check status -

Add the keyword "STRAIGHT_JOIN" to you query. It looks like you have everything in proper logical alignment. You are querying from the main table and joining to all the lookup tables secondary. MySQL sometimes tries to optimize based on table row sizes and will look at a smaller table as a more beneficial path and can choke.
SELECT STRAIGHT_JOIN (rest of query)
Tells MySQL to do the query in the order you provided, don't think for me.
Now, that said, you don't really have a WHERE clause that may be taking advantage of an index. To prevent the need of having to go to every data page for the records, if you have an index on the where clauses, the engine can pre-qualify those records where not null via the index. Assuming that each evaluation plan is an integer (numeric) based "ID" value, I would add an index on
( evaluationPlanId, evaluationPlanLevelOneId, evaluationPlanLevelTwoId, evaluationPlanThreeId )

Related

speed up complex query with joins

I am trying to make this query faster
SELECT
contacts_cstm.case_id_c AS 'Case_id',
CONCAT(cont.first_name, ' ',cont.last_name) AS 'Contact Name',
contacts_cstm.id_c AS 'Id',
'Contacts' AS 'Module',
reso_tax_preparation_cstm.percentage_paid_c as '% Paid'
[... more cols in select ...]
FROM
contacts cont
INNER JOIN contacts_cstm on contacts_cstm.id_c = cont.id and cont.deleted=0
INNER JOIN leads on leads.contact_id = cont.id AND leads.deleted=0
LEFT JOIN leads_aggre_aggregatevalues_1_c ON leads.id = leads_aggre_aggregatevalues_1_c.leads_aggre_aggregatevalues_1leads_ida AND leads_aggre_aggregatevalues_1_c.deleted=0
LEFT JOIN aggre_aggregatevalues_cstm ON leads_aggre_aggregatevalues_1_c.leads_aggre_aggregatevalues_1aggre_aggregatevalues_idb = aggre_aggregatevalues_cstm.id_c
Left JOIN contacts_ccs_ccs_1_c on contacts_ccs_ccs_1_c.contacts_ccs_ccs_1contacts_ida = cont.id AND contacts_ccs_ccs_1_c.deleted = 0
Left JOIN ccs_ccs on ccs_ccs.id = contacts_ccs_ccs_1_c.contacts_ccs_ccs_1ccs_ccs_idb AND ccs_ccs.deleted = 0
LEFT JOIN ccs_ccs_cstm on ccs_ccs_cstm.id_c = ccs_ccs.id
LEFT JOIN users advocate on advocate.id = contacts_cstm.user_id1_c
LEFT JOIN users practitioner on practitioner.id = contacts_cstm.user_id2_c
LEFT JOIN contacts_reso_tax_preparation_1_c on contacts_reso_tax_preparation_1_c.contacts_reso_tax_preparation_1contacts_ida = cont.id
LEFT JOIN reso_tax_preparation_cstm on reso_tax_preparation_cstm.id_c = contacts_reso_tax_preparation_1_c.contacts_reso_tax_preparation_1reso_tax_preparation_idb AND contacts_reso_tax_preparation_1_c.deleted=0
WHERE
(DATEDIFF(NOW(),contacts_cstm.last_contact_date_c) >= 14)
AND (reso_tax_preparation_cstm.percentage_paid_c != '100.00' OR (reso_tax_preparation_cstm.percentage_paid_c = '100.00' AND DATEDIFF(NOW(),contacts_cstm.last_contact_date_c) < 120) )
I tried following things
using Explain to see details
table contacts_reso_tax_preparation_1_c used 113470 rows .
this is the explained output
so these condition
AND (reso_tax_preparation_cstm.percentage_paid_c != '100.00' OR (reso_tax_preparation_cstm.percentage_paid_c = '100.00' AND DATEDIFF(NOW(),contacts_cstm.last_contact_date_c) < 120) )
taking time
moved deleted=0 condition from where condition to join condition
Applied limit 1 to exist queries
innodb to related tables
applied indexed to following columns by these command
ALTER TABLE reso_tax_preparation_cstm ADD INDEX(percentage_paid_c);
ALTER TABLE contacts_cstm ADD INDEX( ctax_status_update_date_c, last_contact_date_c, resolution_type_c, resolution_service_level_c, misc_reso_service_level_c, tax_prep_missing_info_c);
ALTER TABLE contacts_cstm ADD INDEX(user_id2_c);
ALTER TABLE reso_tax_preparation_cstm ADD INDEX(service_status_c);
ALTER TABLE reso_ancillary_services_cstm ADD INDEX(service_status_c);
ALTER TABLE contacts_cstm ADD INDEX(missing_info_final_deadline_c);
trying to split these queries into unions ,but count changes.
query still takes 9 seconds
converted left joins to subqueries
SELECT
contacts_cstm.case_id_c AS 'Case_id',
CONCAT( cont.first_name, ' ', cont.last_name ) AS 'Contact Name',
contacts_cstm.id_c AS 'Id',
'Contacts' AS 'Module',
(select percentage_paid_c AS '% Paid' from
contacts_reso_tax_preparation_1_c
LEFT JOIN
reso_tax_preparation_cstm
ON reso_tax_preparation_cstm.id_c = contacts_reso_tax_preparation_1_c.contacts_reso_tax_preparation_1reso_tax_preparation_idb
AND contacts_reso_tax_preparation_1_c.deleted = 0
where
contacts_reso_tax_preparation_1_c.contacts_reso_tax_preparation_1contacts_ida = cont.id
AND
(
reso_tax_preparation_cstm.percentage_paid_c != '100.00'
OR
(
reso_tax_preparation_cstm.percentage_paid_c = '100.00'
AND DATEDIFF( NOW(), contacts_cstm.last_contact_date_c) < 120
)
)
limit 1
),
DATEDIFF(NOW(), contacts_cstm.last_contact_date_c) AS 'Days since Last Contact',
(
SELECT
COUNT(reqcl_requiredclientinfo.id)
FROM
contacts
INNER JOIN
contacts_cstm
ON contacts_cstm.id_c = contacts.id
LEFT JOIN
contacts_reqcl_requiredclientinfo_1_c
ON contacts_reqcl_requiredclientinfo_1_c.contacts_reqcl_requiredclientinfo_1contacts_ida = contacts.id
LEFT JOIN
reqcl_requiredclientinfo
ON reqcl_requiredclientinfo.id = contacts_reqcl_requiredclientinfo_1_c.contacts_reqcl_requiredclientinfo_1reqcl_requiredclientinfo_idb
AND reqcl_requiredclientinfo.deleted = 0
LEFT JOIN
reqcl_requiredclientinfo_cstm
ON reqcl_requiredclientinfo_cstm.id_c = reqcl_requiredclientinfo.id
WHERE
contacts.id = cont.id
)
AS 'Number of Required Info Records',
contacts_cstm.resolution_type_c AS 'Resolution Type',
CONCAT( advocate.first_name, ' ', advocate.last_name ) AS 'Current Case Advocate',
CONCAT( practitioner.first_name, ' ', advocate.last_name ) AS 'Current Practitioner',
DATEDIFF( NOW(), contacts_cstm.ctax_status_update_date_c) AS 'Days in active Ctax Status ',
contacts_cstm.resolution_service_level_c AS 'Resolution Service Level',
contacts_cstm.tax_preparation_level_c AS 'Tax Prep Service Level',
contacts_cstm.misc_reso_service_level_c AS 'Misc Res Service Level',
ccs_ccs_cstm.ccs_status_c AS `CCS Status`
FROM
contacts cont
INNER JOIN
contacts_cstm
ON contacts_cstm.id_c = cont.id
INNER JOIN
leads
ON leads.contact_id = cont.id
LEFT JOIN
leads_aggre_aggregatevalues_1_c
ON leads.id = leads_aggre_aggregatevalues_1_c.leads_aggre_aggregatevalues_1leads_ida
AND leads_aggre_aggregatevalues_1_c.deleted = 0
LEFT JOIN
aggre_aggregatevalues_cstm
ON leads_aggre_aggregatevalues_1_c.leads_aggre_aggregatevalues_1aggre_aggregatevalues_idb = aggre_aggregatevalues_cstm.id_c
LEFT JOIN
contacts_ccs_ccs_1_c
ON contacts_ccs_ccs_1_c.contacts_ccs_ccs_1contacts_ida = cont.id
AND contacts_ccs_ccs_1_c.deleted = 0
LEFT JOIN
ccs_ccs
ON ccs_ccs.id = contacts_ccs_ccs_1_c.contacts_ccs_ccs_1ccs_ccs_idb
AND ccs_ccs.deleted = 0
LEFT JOIN
ccs_ccs_cstm
ON ccs_ccs_cstm.id_c = ccs_ccs.id
LEFT JOIN
users advocate
ON advocate.id = contacts_cstm.user_id1_c
LEFT JOIN
users practitioner
ON practitioner.id = contacts_cstm.user_id2_c
this reduces time and count , but i wanted to be sure this is right
what more can i try
Avoid un-sargable constructs:
AND DATEDIFF(NOW(),contacts_cstm.last_contact_date_c) < 120)
-->
AND contacts_cstm.last_contact_date_c > NOW() - INTERVAL 120 DAY
OR is hard to Optimize. If you can't get rid of it, we can talk about using UNION.
Remove any Joins that do not actually participate in the query.
Single-column indexes are sometimes not as good as 'composite' (multi-column) indexes.
Some of these indexes may help with the original query andor with the 'subquery' reformulation:
aggre_aggregatevalues_cstm: INDEX(id_c)
ccs_ccs_cstm: INDEX(id_c, ccs_status_c)
contacts_cstm: INDEX(id_c)
contacts_cstm: INDEX(last_contact_date_c, id_c, case_id_c, user_id1_c, user_id2_c)
contacts_ccs_ccs_1_c: INDEX(contacts_ccs_ccs_1contacts_ida, deleted, contacts_ccs_ccs_1ccs_ccs_idb)
contacts_reso_tax_preparation_1_c: INDEX(contacts_reso_tax_preparation_1contacts_ida, contacts_reso_tax_preparation_1reso_tax_preparation_idb, deleted)
contacts_reqcl_requiredclientinfo_1_c: INDEX(contacts_reqcl_requiredclientinfo_1contacts_ida, contacts_reqcl_requiredclientinfo_1reqcl_requiredclientinfo_idb)
leads: INDEX(contact_id, deleted, id)
leads: INDEX(contact_id, id)
leads_aggre_aggregatevalues_1_c: INDEX(leads_aggre_aggregatevalues_1leads_ida, deleted, leads_aggre_aggregatevalues_1aggre_aggregatevalues_idb)
reso_tax_preparation_cstm: INDEX(percentage_paid_c, id_c)
reqcl_requiredclientinfo_cstm: INDEX(id_c)
When adding a composite index, DROP index(es) with the same leading columns.
That is, when you have both INDEX(a) and INDEX(a,b), toss the former.

inner join in Sql Subquery

I am trying to run this query with using subquery but not able to fetch my result .is any one here to help me in geting it correct.
SELECT u.uv_id ID
, d.sd_code Code
, u.uv_name Title
, u.uv_nirf Nirf
, (SELECT sd_code
FROM vm_university_type t
JOIN vm_seo_detail d
ON t.ut_id = d.sd_ty_id
AND d.sd_ty = 'vm_university_type') AS 'University Type'
, a.ab_name 'Approved By'
, u.uv_seats Seats
, g.ug_name 'University Group'
FROM vm_universities u
JOIN vm_seo_detail d
ON u.uv_id = d.sd_ty_id
AND d.sd_ty = 'vm_universities'
JOIN vm_university_type t
ON u.uv_ut_id = t.ut_id
JOIN vm_approved_by a
ON u.uv_ab_id = a.ab_id
JOIN vm_caste c
ON u.uv_c_id = c.caste_id
JOIN vm_university_groups g
ON u.uv_ug_ids = g.ug_id;
i got this error Subquery returns more than 1 row
(SELECT `sd_code` FROM vm_university_type INNER JOIN vm_seo_detail ON (vm_university_type.ut_id = vm_seo_detail.sd_ty_id AND vm_seo_detail.sd_ty = 'vm_university_type') WHERE vm_university_type.ut_id=vm_universities.uv_ut_id ) AS 'University Type' ,
You do not need subquery at all. The column Code in SELECT statement contains University Type
Try below query.
SELECT vm_universities.uv_id AS 'ID' , vm_seo_detail.sd_code AS 'Code',
vm_universities.uv_name AS 'Title' , vm_universities.uv_nirf AS 'Nirf',
vm_approved_by.ab_name AS 'Approved By' , vm_universities.uv_seats as 'Seats',
vm_university_groups.ug_name AS 'University Group'
FROM vm_universities INNER JOIN vm_seo_detail
ON (vm_universities.uv_id = vm_seo_detail.sd_ty_id
AND vm_seo_detail.sd_ty = 'vm_universities')
INNER JOIN vm_university_type
ON (vm_universities.uv_ut_id = vm_university_type.ut_id)
INNER JOIN vm_approved_by
ON (vm_universities.uv_ab_id = vm_approved_by.ab_id)
INNER JOIN vm_caste
ON (vm_universities.uv_c_id = vm_caste.caste_id)
INNER JOIN vm_university_groups
ON (vm_universities.uv_ug_ids = vm_university_groups.ug_id);
SELECT `sd_code` FROM vm_university_type INNER JOIN vm_seo_detail ON (vm_university_type.ut_id = vm_seo_detail.sd_ty_id AND vm_seo_detail.sd_ty = 'vm_university_type')
looks like you forgot WHERE section in subquery, that will bind it to main query. something like
WHERE vm_university_type.ut_id=vm_universities.uv_ut_id
ps. and why you need this subquery at all, if you already join with vm_university_type in main query?

LEFT JOIN, INNER JOIN AND UNIONS, HOW TO ORDER BY

We have a SQL query that produces a report. We have sucussfully joined our settings table to update the integer values with the correct items, We have also used a union to display our three types of users.
We would like to take this query and order it by the e_job.objId field, however we are finding it really difficult with the multiple joins and unions.
If anyone could help it would be appreciated.
SELECT e_job.objId AS 'Job Number', e_student.Lastname AS 'Last Name', e_student.Name AS 'First Name', e_asset.objId AS 'Asset Number', e_asset.aSerialNumber AS 'Serial Number', si.sLabel AS 'Issue', srt.sLabel AS 'Repair Type', ss.sLabel As 'Status', e_job.note 'Description',FROM_UNIXTIME(e_job.jCreatedAt,'%d/%m/%y') AS 'Date Created'
FROM e_job
INNER JOIN e_student ON e_job.jName = e_student.username
INNER JOIN e_asset ON e_job.jAsset = e_asset.aId
LEFT JOIN e_settings si ON si.sKey = 'job_issue' AND si.sValue = e_job.jIssue
LEFT JOIN e_settings srt ON srt.sKey = 'job_rep_type' AND srt.sValue = e_job.jRepairType
LEFT JOIN e_settings ss ON ss.sKey = 'job_status' AND ss.sValue = e_job.jStatus
WHERE jStatus = 1 && jRepairType = 2
UNION
SELECT e_job.objId AS 'Job Number', e_teachers.Lastname AS 'Last Name', e_teachers.Name AS 'First Name', e_asset.objId AS 'Asset Number', e_asset.aSerialNumber AS 'Serial Number', si.sLabel AS 'Issue', srt.sLabel AS 'Repair Type', ss.sLabel As 'Status', e_job.note 'Description',FROM_UNIXTIME(e_job.jCreatedAt,'%d/%m/%y') AS 'Date Created'
FROM e_job
INNER JOIN e_teachers ON e_job.jName = e_teachers.username
INNER JOIN e_asset ON e_job.jAsset = e_asset.aId
LEFT JOIN e_settings si ON si.sKey = 'job_issue' AND si.sValue = e_job.jIssue
LEFT JOIN e_settings srt ON srt.sKey = 'job_rep_type' AND srt.sValue = e_job.jRepairType
LEFT JOIN e_settings ss ON ss.sKey = 'job_status' AND ss.sValue = e_job.jStatus
WHERE jStatus = 1 && jRepairType = 2
UNION
SELECT e_job.objId AS 'Job Number', e_supportStaff.Lastname AS 'Last Name', e_supportStaff.Name AS 'First Name', e_asset.objId AS 'Asset Number', e_asset.aSerialNumber AS 'Serial Number', si.sLabel AS 'Issue', srt.sLabel AS 'Repair Type', ss.sLabel As 'Status', e_job.note 'Description',FROM_UNIXTIME(e_job.jCreatedAt,'%d/%m/%y') AS 'Date Created'
FROM e_job
INNER JOIN e_supportStaff ON e_job.jName = e_supportStaff.username
INNER JOIN e_asset ON e_job.jAsset = e_asset.aId
LEFT JOIN e_settings si ON si.sKey = 'job_issue' AND si.sValue = e_job.jIssue
LEFT JOIN e_settings srt ON srt.sKey = 'job_rep_type' AND srt.sValue = e_job.jRepairType
LEFT JOIN e_settings ss ON ss.sKey = 'job_status' AND ss.sValue = e_job.jStatus
WHERE jStatus = 1 && jRepairType = 2
Thank you
If you add an ORDER BY clause to the end of the query it should apply to the entire result set. You can try adding this:
ORDER BY `Job Number`
Also, you don't need to specify aliases in union queries other than the first one. The first set of aliases are what stick.

Select by multiple values in left join

Working with following structure, how can I select a subset of requests respecting multiple conditions in this 1:n relation?
# Table 1: Request
uid
name
# Table 2: Additional Information
uid
type
value
request
Note for table 2: type can be anything, i.e. 'product_name' or 'rating'.
If I'd just want to select Requests by a given product_name I can do this:
SELECT * FROM request as r
LEFT JOIN additional_information as i
ON r.uid = i.request
WHERE i.type = 'product' AND i.value = 'Product Name'
I'm stuck at what my statement must look like if I want to select Requests by a given product_name AND rating. I have tried to simply add another join but this gave me all requests that related to a given product_name as well as all requests related to a given rating. I need the statement to respect both conditions.
This, as mentioned, does not work for me.
SELECT * FROM request as r
LEFT JOIN additional_information as i
ON r.uid = i.request
LEFT JOIN additional_information as a
ON r.uid = a.request
WHERE i.type = 'product' AND i.value = 'Product Name'
OR a.type = 'rating' AND a.value = 1
Appreciate the help!
Move those conditions from WHERE to JOIN ON condition like
SELECT * FROM request as r
LEFT JOIN additional_information as i
ON r.uid = i.request
AND i.type = 'product' AND i.value = 'Product Name'
LEFT JOIN additional_information as a
ON r.uid = a.request
AND a.type = 'rating' AND a.value = 1;
And Yes absolutely, considering the valuable comment (which missed) from Strwabery, instead of doing a select * or select r.* you might actually want to specify the column names you want to fetch which is better than * performance wise since you are not getting unnecessary data using projection; unless you really want to fetch everything.
It might be slow from the other offering since it is joining to your additional data TWICE, once for product, again on rating. This should probably be changed to a single left-join otherwise you could get a Cartesian result bloating your answer.
SELECT *
FROM
request as r
LEFT JOIN additional_information as i
ON r.uid = i.request
AND ( ( i.type = 'product' AND i.value = 'Product Name' )
OR ( i.type = 'rating' AND i.value = 1 );

Combine conditions with AND in Mysql ON clause

I have the following query, that I use to filter rows based on software_id and level.
I've put the conditions in the ON-Clause since I still want rows returned, where there are no corresponding rows in the JobadvertsSoftware Table.
SELECT `Jobadvert`.`id` FROM `jobadverts` AS `Jobadvert`
LEFT JOIN `users` AS `User` ON (`Jobadvert`.`user_id` = `User`.`id`)
LEFT JOIN `jobadverts_softwares` AS `JobadvertsSoftware_0` ON
(`Jobadvert`.`id` = 'JobadvertsSoftware_0.jobadvert_id' AND
(`JobadvertsSoftware_0`.`software_id` = '32' AND
`JobadvertsSoftware_0`.`level` IN ('1', 4)))
WHERE `Jobadvert`.`active` = 1 AND `User`.`premium` = '1' AND
Jobadvert`.`department_id` = (5)
GROUP BY `Jobadvert`.`id`
The problem is that it also returns JobadvertsSoftware-rows where level is e.g. 2
Again, if I put that in the WHERE clause it will filter out the rows where there are not JobadvertsSoftware which it shouldn't do.
How can I tell MySQL to return all rows of Jobadvert, where the given software_id AND the level matches or are NULL?
Try this:
SELECT `Jobadvert`.`id`, `JobadvertsSoftware_0`.`level`
FROM `jobadverts` AS `Jobadvert`
LEFT JOIN `users` AS `User` ON (`Jobadvert`.`user_id` = `User`.`id`)
INNER JOIN `jobadverts_softwares` AS `JobadvertsSoftware_0` ON
(`Jobadvert`.`id` = 'JobadvertsSoftware_0.jobadvert_id' AND
(`JobadvertsSoftware_0`.`software_id` = '32' AND
`JobadvertsSoftware_0`.`level` IN ('1', 4)))
WHERE `Jobadvert`.`active` = 1 AND `User`.`premium` = '1' AND
Jobadvert`.`department_id` = (5)
GROUP BY `Jobadvert`.`id`
Saludos!
Try this( it's a bit unclear if some fields are numeric on string, it might be corrected):
SELECT distinct(`Jobadvert`.`id`) FROM `jobadverts` AS `Jobadvert`
LEFT JOIN `users` AS `User` ON (`Jobadvert`.`user_id` = `User`.`id`)
LEFT JOIN `jobadverts_softwares` AS `JobadvertsSoftware_0`
ON `Jobadvert`.`id` = `JobadvertsSoftware_0.jobadvert_id`
WHERE
`Jobadvert`.`active` = 1
AND `User`.`premium` = '1'
AND Jobadvert`.`department_id` = (5)
AND JobadvertsSoftware_0`.`software_id` = '32'
AND (`JobadvertsSoftware_0`.`level` IN (1, 4) OR `JobadvertsSoftware_0`.`level` is NULL)
Assuming the level parameters in your ON clause is not needed for the join you can do a nested SELECT on your Software table to clear out the data you do not need first:
SELECT * FROM jobadverts_softwares
WHERE
(`software_id` = 32 OR `software_id` IS NULL) --Select all software_id that are 32 or null
AND
`level` IN (1, 4)
Then you can incorporate this as a nested statement in your main SQL query so you only join on the data which is filtered in your LEFT JOIN but keep any null values that you needed:
SELECT `Jobadvert`.`id`
FROM `jobadverts` AS `Jobadvert`
LEFT JOIN `users` AS `User`
ON `Jobadvert`.`user_id` = `User`.`id`
LEFT JOIN
( --Software Subquery
SELECT `jobadvert_id`, `level` FROM jobadverts_softwares
WHERE
(`software_id` = 32 OR `software_id` IS NULL) --Select all software_id that are 32 or null
AND
`level` IN (1, 4)
) AS `software_subquery`
ON `Jobadvert`.`id` = `software_subquery`.`jobadvert_id`
WHERE
`Jobadvert`.`active` = 1
AND
`User`.`premium` = '1'
AND
`Jobadvert`.`department_id` = 5
ORDER BY `Jobadvert`.`id` --Changed GROUP BY to ORDER BY as not needed
This is untested but try it out and see if this will help.
Try this:
SELECT j.id
FROM jobadverts j
LEFT JOIN User u ON (j.user_id = u.id)
LEFT JOIN jobadverts_softwares AS js ON
(j.id = js.jobadvert_id)
WHERE j.active = 1
AND u.premium = '1'
AND j.department_id = (5)
AND js.software_id` = '32'
AND js.level IN ('1', 4)))
You won't need a GROUP BY unless summing data in some way.