Combine conditions with AND in Mysql ON clause - mysql

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.

Related

OR condition with Joins using cakephp and mysql

Iam searching a keyword in solr and it returns matched resume id's,when I got the result from solr I am searching those documents and getting matched job seekers from my database.
Now my question is have to get the record if it match in documents or in job seekers skills i.e job_seekers.skills column how to write the query..
Here is my existing query..
SELECT *
FROM `job_seekers` AS `JobSeeker`
LEFT JOIN `job_seeker_documents` AS `JobSeekerDocument` ON (`JobSeeker`.`id` = `JobSeekerDocument`.`job_seeker_id` AND `doc_attachment` IN ('1457448773Jan.doc', '1457448764Eric.doc', 'Vijal_Chokshi_Profile.doc', 'Deborah_Project manager_Profile..docx'))
LEFT JOIN `config_work_authorizations` AS `ConfigWorkAuthorization` ON (`JobSeeker`.`work_authorization` = `ConfigWorkAuthorization`.`id`)
LEFT JOIN `employees` AS `Employee` ON (`Employee`.`job_seeker_id` = `JobSeeker`.`id`)
WHERE `JobSeeker`.`company_id` = 11 AND `JobSeeker`.`skills` = 'java' AND `JobSeeker`.`bench_status` IN (0, 1) AND (select count(*) from employee_jobs where `employee_jobs`.`employee_id`=`Employee`.`id` and `employee_jobs`.`job_status` =1 ) = 0 GROUP BY `JobSeeker`.`id` HAVING (COUNT(`JobSeekerDocument`.`id`) > 0 );
you can write or condition in brackets i.e. () like
(`JobSeeker`.`skills` = 'java' OR `JobSeekerDocument`.`skills` = 'java')
In your query
SELECT *
FROM `job_seekers` AS `JobSeeker`
LEFT JOIN `job_seeker_documents` AS `JobSeekerDocument` ON (`JobSeeker`.`id` = `JobSeekerDocument`.`job_seeker_id` AND `doc_attachment` IN ('1457448773Jan.doc', '1457448764Eric.doc', 'Vijal_Chokshi_Profile.doc', 'Deborah_Project manager_Profile..docx'))
LEFT JOIN `config_work_authorizations` AS `ConfigWorkAuthorization` ON (`JobSeeker`.`work_authorization` = `ConfigWorkAuthorization`.`id`)
LEFT JOIN `employees` AS `Employee` ON (`Employee`.`job_seeker_id` = `JobSeeker`.`id`)
WHERE `JobSeeker`.`company_id` = 11
AND (`JobSeeker`.`skills` = 'java' OR `JobSeekerDocument`.`skills` = 'java')
AND `JobSeeker`.`bench_status` IN (0, 1)
AND (select count(*) from employee_jobs where `employee_jobs`.`employee_id`=`Employee`.`id` and `employee_jobs`.`job_status` =1 ) = 0
GROUP BY `JobSeeker`.`id`
HAVING (COUNT(`JobSeekerDocument`.`id`) > 0 );

Like best performance in nested query

I have a principal requet with 2 requets in. I have a problem in my second nested query, I have a condition on id and if I made my request id = 10 takes a long time to execute, so if I replace it by id LIKE 10 my request execute in one second.
Here the request:
SELECT SQL_NO_CACHE contact_groupe.id_contact_groupe
FROM toto.contact_groupe
LEFT JOIN toto.`contact` AS `contact`
ON ((toto.contact_groupe.id_contact_groupe = toto.contact.id_contact_groupe))
LEFT JOIN toto.`project` AS `project`
ON ((toto.contact_groupe.id_contact_groupe = toto.project.id_contact_groupe)
AND ( toto.project.id_project
IN (
SELECT MAX(toto.project.id_project)
FROM toto.project
WHERE ( toto.contact_groupe.id_contact_groupe = toto.project.id_contact_groupe )
) ))
LEFT JOIN toto.`phase` AS `phase`
ON ((project.id_phase = toto.phase.id_phase))
LEFT JOIN sql_base.`user` AS `user_suivi`
ON ((toto.contact_groupe.id_user_suivi = user_suivi.id_user))
WHERE ( en_attente = '0' AND contact_groupe.id_contact_groupe
IN (
SELECT DISTINCT(contact_groupe.id_contact_groupe)
FROM toto.contact_groupe
LEFT JOIN toto.`contact` AS `contact`
ON ((toto.contact_groupe.id_contact_groupe = toto.contact.id_contact_groupe)
LEFT JOIN toto.`source_contact_groupe` AS `source_contact_groupe`
ON ((toto.contact_groupe.id_contact_groupe = toto.source_contact_groupe.id_contact_groupe))
LEFT JOIN toto.`project` AS `project`
ON ((toto.contact_groupe.id_contact_groupe = toto.project.id_contact_groupe))
LEFT JOIN toto.`remarque` AS `remarque`
ON ((toto.contact_groupe.id_contact_groupe = toto.remarque.id_contact_groupe))
LEFT JOIN toto.`project_type_construction_options` AS `project_type_construction_options`
ON ((project.id_project = toto.project_type_construction_options.id_project))
LEFT JOIN toto.`project_concurrent` AS `project_concurrent`
ON ((project.id_project = toto.project_concurrent.id_project))
LEFT JOIN toto.`telephone` AS `telephone`
ON ((contact.id_contact = toto.telephone.id_contact))
WHERE ( en_attente = '0' AND ( toto.project.id_project = '10' ) AND toto.contact_groupe.id_entreprise = '2' )
)
AND toto.contact_groupe.id_entreprise = '2' )
ORDER BY toto.contact_groupe.id_contact_groupe ASC
the line is the following problem toto.project.id_project = '10' and I don't understand why the time to execute request is so different between = and LIKE
Let's start with your subquery. Those 17 lines that you've written are functionally identical to this, so why not use this instead?
SELECT DISTINCT g.id_contact_groupe
FROM contact_groupe g
JOIN project p
ON p.id_contact_groupe = g.id_contact_groupe
WHERE g.en_attente = 0
AND p.id_project = 10
AND g.id_entreprise = 2

mysql join with multiple conditions (not OR but AND)

i have problem with join table and use multiple conditions...
My code:
SELECT * FROM
(SELECT sid, MAX(info_date_add) AS max_info_date_add FROM skiresort GROUP BY sid) skiresort_max
INNER JOIN skiresort
ON
skiresort_max.sid = skiresort.sid AND
skiresort_max.max_info_date_add = skiresort.info_date_add
JOIN skiresort_theme_value
ON skiresort_theme_value.skiresort_id = skiresort.id
WHERE
skiresort_theme_value.skiresort_theme_id = '1' AND
skiresort_theme_value.skiresort_theme_id = '2' AND
skiresort_theme_value.skiresort_theme_id = '4'
GROUP BY skiresort.sid
ORDER BY skiresort.title_en
In this code, the conditions are in WHERE clausule. I also tried to put in into JOIN ON (...) but it also didn't work.
When i have only one condition it works. I read some articles about using OR instead of AND, it worked but not as i expected. I need to search only rows with certain IDs (multiple).
why not use this instead of many conditions.
WHERE
skiresort_theme_value.skiresort_theme_id in (1, 2,4)
GROUP BY skiresort.sid
HAVING COUNT(DISTINCT skiresort_theme_value.skiresort_theme_id) = 3
ORDER BY skiresort.title_en
when add condition to WHERE, condition must be from FROM tbl
add condition JOIN ON
Try this:
SELECT * FROM
(SELECT sid, MAX(info_date_add) AS max_info_date_add FROM skiresort GROUP BY sid) skiresort_max
INNER JOIN skiresort
ON
skiresort_max.sid = skiresort.sid AND
skiresort_max.max_info_date_add = skiresort.info_date_add
JOIN skiresort_theme_value
ON (skiresort_theme_value.skiresort_id = skiresort.id AND skiresort_theme_value.skiresort_theme_id = '1' AND skiresort_theme_value.skiresort_theme_id = '2' AND skiresort_theme_value.skiresort_theme_id = '4')
GROUP BY skiresort.sid
ORDER BY skiresort.title_en

Counting rows from a big mysql query (zend)

I a developing in zend and have a rather large mysql query. The query works fine and i get the list I expect. I am doing this using Select->Where.... below is the query.
SELECT DISTINCT `d`.* FROM `deliverable` AS `d` INNER JOIN `groups` AS `g1` ON d.id = g1.deliverable_id INNER JOIN `groupmembers` AS `gm1` ON g1.id = gm1.group_id LEFT JOIN `connection` AS `c` ON d.id = c.downstreamnode_id LEFT JOIN `deliverable` AS `d1` ON c.upstreamnode_id = d1.id INNER JOIN `deliverable` AS `d2` ON CASE WHEN d1.id IS NULL THEN d.id ELSE d1.id END = d2.id INNER JOIN `groups` AS `g` ON d2.id = g.deliverable_id INNER JOIN `groupmembers` AS `gm` ON g.id = gm.group_id WHERE (g1.group_type = 100) AND (gm1.member_id = 1) AND (c.downstreamnode_id IS NULL OR d.restrict_access = 1) AND (g.group_type = 100 OR g.group_type = 110) AND (gm.member_id = 1) AND (d.deliverable_type = 110 OR d.deliverable_type = 100) GROUP BY CASE WHEN c.downstreamnode_id IS NULL THEN d.id ELSE c.downstreamnode_id END
Only problem is when I try to count the rows in a mysql query I only get 1 returned. below is the query
SELECT DISTINCT count(*) AS `rowCount` FROM `deliverable` AS `d` INNER JOIN `groups` AS `g1` ON d.id = g1.deliverable_id INNER JOIN `groupmembers` AS `gm1` ON g1.id = gm1.group_id LEFT JOIN `connection` AS `c` ON d.id = c.downstreamnode_id LEFT JOIN `deliverable` AS `d1` ON c.upstreamnode_id = d1.id INNER JOIN `deliverable` AS `d2` ON CASE WHEN d1.id IS NULL THEN d.id ELSE d1.id END = d2.id INNER JOIN `groups` AS `g` ON d2.id = g.deliverable_id INNER JOIN `groupmembers` AS `gm` ON g.id = gm.group_id WHERE (g1.group_type = 100) AND (gm1.member_id = 1) AND (c.downstreamnode_id IS NULL OR d.restrict_access = 1) AND (g.group_type = 100 OR g.group_type = 110) AND (gm.member_id = 1) AND (d.deliverable_type = 110 OR d.deliverable_type = 100) GROUP BY CASE WHEN c.downstreamnode_id IS NULL THEN d.id ELSE c.downstreamnode_id END
i generate this from by using the same 'select' that generated the first query but I reset the columns and add count in.
$this->getAdapter()->setFetchMode(Zend_Db::FETCH_ASSOC);
$select
->reset( Zend_Db_Select::COLUMNS)
->columns(array('count('.$column.') as rowCount'));
$rowCount = $this->getAdapter()->fetchOne($select);
This method works fine for all my other queries only this one i am having trouble with. I suspect it has something to do the 'CASE' I have in there but it is strange because I am getting the correct rows the the first query. Any ideas. Thanks.
FYI below are two queries that I have working successfully.
SELECT DISTINCT `po`.* FROM `post` AS `po` INNER JOIN `postinfo` AS `p` ON po.postinfo_id = p.id WHERE (p.creator_id = 1) ORDER BY `p`.`date_created` DESC
SELECT DISTINCT count(*) AS `rowCount` FROM `post` AS `po` INNER JOIN `postinfo` AS `p` ON po.postinfo_id = p.id WHERE (p.creator_id = 1) ORDER BY `p`.`date_created` DESC
In this one I have 4 rows returned in the first query and 'int 4' returned for the second one. Does anyone know why it doesnt work for the big query?
Move your DISTINCT.
SELECT COUNT(DISTINCT `po`.*) AS `rowCount` ...
Ok figured it out It was the GROUP BY that was causing only 1 result to be returned. Thanks Interrobang for you help I am sure that using DISTINCT incorrectly will have caused me a headache in the future.
Try using SQL_CALC_FOUND_ROWS in your query?
http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows
Using SQL_CALC_FOUND_ROWS is mysql-specific, but it's pretty nice for getting a full record count even when your initial query contains a limit. Once you get the count, don't include SQL_CALC_FOUND_ROWS in subsequent queries for extra records since that will cause extra load on your query.
Your initial query would be:
SELECT SQL_CALC_FOUND_ROWS DISTINCT `d`.* FROM `deliverable` AS `d` INNER JOIN `groups` ...
You'll have to do a subsequent call after your initial query executes to get the count by doing a SELECT FOUND_ROWS().
If you do a little searching, you'll find someone who extended Zend_Db_Select to include this ability.

MySQL LEFT JOIN do not return all results

I have a query that JOINs some tables to get a list of products including prices, images, country etc.
"product_images" table can have zero or more images but only the default image should be returned. My problem is that in any case the query should return a result for the product even if there is no image in the "product_images" table for that particular product.
The first query example will return a row for each product but just return a random image:
SELECT `cp`.`category_id`, `p`.`id`, `p`.`master`, `p`.`status`, `p`.`sortorder`, `p`.`sku`, `p`.`stock`, `pd`.`name`, `pd`.`short_description`, `pd`.`description`, `pd`.`slug`, `pi`.`image`, `pi`.`path`
FROM `categories_products` AS `cp`
JOIN `products` AS `p` ON (`cp`.`product_id` = `p`.`id`)
JOIN `product_descriptions` AS `pd`
ON (`pd`.`product_id` = `p`.`id`)
LEFT JOIN `product_images` AS `pi`
ON (`pi`.`product_id` = `p`.`id`)
WHERE `cp`.`category_id` = 34
AND `pd`.`locale_id` = 1
AND `p`.`master` = '0'
AND `p`.`status` = '1'
AND `p`.`accessible` = '1'
AND `pd`.`status` = '1'
GROUP BY `p`.`id`
ORDER BY `p`.`sortorder`
Below query will return the default image. But if there is no image in "product_images" the row for that product will not be retrieved. The only difference here is this part: "AND pi.preset = 1"
SELECT `cp`.`category_id`, `p`.`id`, `p`.`master`, `p`.`status`, `p`.`sortorder`, `p`.`sku`, `p`.`stock`, `pd`.`name`, `pd`.`short_description`, `pd`.`description`, `pd`.`slug`, `pi`.`image`, `pi`.`path`
FROM `categories_products` AS `cp`
JOIN `products` AS `p` ON (`cp`.`product_id` = `p`.`id`)
JOIN `product_descriptions` AS `pd`
ON (`pd`.`product_id` = `p`.`id`)
LEFT JOIN `product_images` AS `pi`
ON (`pi`.`product_id` = `p`.`id`)
WHERE `cp`.`category_id` = 34
AND `pi`.`preset` = 1
AND `pd`.`locale_id` = 1
AND `p`.`master` = '0'
AND `p`.`status` = '1'
AND `p`.`accessible` = '1'
AND `pd`.`status` = '1'
GROUP BY `p`.`id`
ORDER BY `p`.`sortorder`
`pi`.`preset` = 1
in WHERE defeats your goal (your LEFT JOIN behaves like INNER ) . Move it to ON:
LEFT JOIN `product_images` AS `pi`
ON (`pi`.`product_id` = `p`.`id` AND `pi`.`preset` = 1)
You may prefer to use a subquery:
LEFT JOIN (SELECT * FROM product_images WHERE preset = 1) AS pi ON ...
Otherwise, the WHERE clause is applied to the entire query, and if there's no image, WHERE pi.preset=1 will reduce your search set to zero rows.