Find a partial match in MySQL query with multiple "OR" - mysql

I need to find partial or full matches in a MySQL query. I am performing queries in multiple tables using 'OR' and need to know whether all conditions have been met or just some of them.
I believe the easiest way to do this would be to create a new column called 'partial' which would either be 0 or 1 (Feel free to correct me if I am wrong).
Here is my query:
SELECT
id, confirmed, name, addressLine1, addressLine2, addressCity, addressPostcode,
addressLat, addressLon,
(6371 * acos( cos( radians( '53.649779' ) )
* cos( radians( addressLat ) )
* cos( radians( addressLon ) - radians( '-1.6026266' ) )
+ sin( radians( '53.649779' ) ) * sin( radians( addressLat ) ) )
) distance
FROM TABLE_NAME
WHERE active = '1'
AND deleted = '0'
AND
(
id < 0
OR
id IN
(
SELECT establishmentID
FROM appEstablishmentDrinks
WHERE active = '1'
AND deleted = '0'
AND manufacturerDrinkID IN (101)
GROUP BY establishmentID
HAVING count(distinct manufacturerDrinkID) = 1
)
OR
id IN
(
SELECT establishmentID
FROM appEstablishmentFacilities
WHERE active = '1'
AND deleted = '0'
AND facilityID IN (37)
)
)
HAVING distance < '15'

In MySQL true = 1 and false = 0. So simply add conditions: (id < 0) + (id in (...)) + (id in (...)) and check whether you got all three matches or less.
SELECT
id, confirmed, name, addressLine1, addressLine2, addressCity, addressPostcode,
addressLat, addressLon, distance,
case when count_matches = 3 then 'full' else 'partial' end as matching
FROM
(
SELECT
id, confirmed, name, addressLine1, addressLine2, addressCity, addressPostcode,
addressLat, addressLon,
(6371 * acos( cos( radians( 53.649779 ) )
* cos( radians( addressLat ) )
* cos( radians( addressLon ) - radians( -1.6026266 ) )
+ sin( radians( 53.649779 ) ) * sin( radians( addressLat ) ) )
) as distance,
(id < 0 )
+
(
id IN
(
SELECT establishmentID
FROM appEstablishmentDrinks
WHERE active = 1
AND deleted = 0
AND manufacturerDrinkID IN (101)
GROUP BY establishmentID
HAVING count(distinct manufacturerDrinkID) = 1
)
)
+
(
id IN
(
SELECT establishmentID
FROM appEstablishmentFacilities
WHERE active = 1
AND deleted = 0
AND facilityID IN (37)
)
) as count_matches
FROM TABLE_NAME
WHERE active = 1
AND deleted = 0
) x
WHERE distance < 15
AND count_matches > 0;

Related

Mysql query with multiple having conditions creating error

I am trying multiple having but problem is with multiple having conditions any one guide me how to adjust two having in same query
Here is SQL Query :
SELECT schools.*,
schools.required_gpa AS gpa,
(college_act_scores.min_act + college_act_scores.max_act)/2 AS act_avrg ,
(college_sat_scores.min_sat + college_sat_scores.max_sat)/2 AS sat_avrg,
(6371 * Acos( Cos( Radians(31.4699398) ) * Cos( Radians( latitude ) ) * Cos( Radians( longtitude ) - Radians(74.3096108) ) + Sin( Radians(31.4699398) ) * Sin( Radians( latitude ) ) ) ) AS distance
FROM schools
LEFT JOIN college_paying1
ON college_paying1.college_id = schools.id
LEFT JOIN college_act_scores
ON (
college_act_scores.college_id = schools.id
AND college_act_scores.college_child_sub_cat_id = 144)
LEFT JOIN college_sat_scores
ON (
college_sat_scores.college_id = schools.id
AND college_sat_scores.college_child_sub_cat_id = 136)
WHERE college_paying1.on_campus >= 0
AND college_paying1.on_campus <=80348
AND college_paying1.college_child_sub_cat_id =120
HAVING (
act_avrg BETWEEN 0 AND 36)
having (
sat_avrg BETWEEN 0 AND 1600)
GROUP BY schools.id
ORDER BY distance ASC limit 0, 10
You need to move the HAVING clause after GROUP BY. Document here
This should work:
select schools.*,schools.required_gpa as gpa,
(college_act_scores.min_act + college_act_scores.max_act)/2 as act_avrg ,
(college_sat_scores.min_sat + college_sat_scores.max_sat)/2 as sat_avrg,
(6371 * acos( cos( radians(31.4699398) ) * cos( radians( latitude ) ) * cos( radians( longtitude ) - radians(74.3096108) ) + sin( radians(31.4699398) ) * sin( radians( latitude ) ) ) ) AS distance
from schools
left join college_paying1 on college_paying1.college_id = schools.id
left join college_act_scores on (college_act_scores.college_id = schools.id
AND college_act_scores.college_child_sub_cat_id = 144)
left join college_sat_scores on (college_sat_scores.college_id = schools.id
AND college_sat_scores.college_child_sub_cat_id = 136)
where college_paying1.on_campus >= 0
and college_paying1.on_campus <=80348
and college_paying1.college_child_sub_Cat_id =120
GROUP BY schools.id
HAVING ( act_avrg BETWEEN 0 AND 36) AND ( sat_avrg BETWEEN 0 AND 1600)
order by distance asc
LIMIT 0 , 10
Hope this helps! Cheers!
Instead of
HAVING ( act_avrg BETWEEN 0 AND 36) HAVING ( sat_avrg BETWEEN 0 AND 1600)
Put
HAVING (act_avrg BETWEEN 0 AND 36) AND (sat_avrg BETWEEN 0 AND 1600)

Converting 'WITH CTE' MSSQL to MySQL

I realize that this doesn't directly translate from MSSQL to MySQL but I'm not not sure how to make it work. Any help that you have is appreciated.
;WITH cte As (
SELECT
post_id,
status,
dealer,
distributor,
SUM(
3959 * acos(
cos( radians(%f) ) *
cos( radians( lat ) ) *
cos( radians( lng ) - radians(%f) ) +
sin( radians(%f) ) *
sin( radians( lat ) )
)
)
AS DISTANCE
FROM wp_geodatastore
GROUP BY post_id, status, dealer, distributor
)
SELECT post_id, status, dealer, distributor, DISTANCE
FROM cte WHERE (DISTANCE < %d)
AND status = 'publish' AND dealer = 'on' AND distributor = 'on'
ORDER BY DISTANCE
OFFSET %d ROWS
FETCH NEXT %d ROWS ONLY;
Just make it a subquery:
SELECT post_id, status, dealer, distributor, DISTANCE
FROM (SELECT post_id, status, dealer, distributor,
SUM( 3959 * acos(
cos( radians(%f) ) *
cos( radians( lat ) ) *
cos( radians( lng ) - radians(%f) ) +
sin( radians(%f) ) *
sin( radians( lat ) )
)
) AS DISTANCE
FROM wp_geodatastore
GROUP BY post_id, status, dealer, distributor
) cte
WHERE (DISTANCE < %d) AND
status = 'publish' AND dealer = 'on' AND distributor = 'on'
ORDER BY DISTANCE
OFFSET %d ROWS
FETCH NEXT %d ROWS ONLY;

Mysql JOIN multiple tables with latitude and longitude

I'm trying to display advertisements relevant to data of the user.
Here, data is Latitude and longitude.
ADS table: ad to display with ad name, ad text, latitude and longitude
Tables with data of the user:
TABLE1: user id + latitude and longitude,
TABLE2: user id + latitude and longitude,
TABLE3: user id + latitude and longitude,
TABLE4: user id + latitude and longitude
The purpose is to display an ad, when the latitude and longitude of the ad matches the latitude and longtitude of one or more lines in the 4 tables in a range of 10km and limit by 3 results.
It's working when linking one ad with one table in range of 10km, but doesn't with more tables.
- I'm not comfortable with OUTER JOINS -
My query looks like this and I'm pretty sure I'm going wrong...
SELECT ADS.name, ADS.text,
( 6371 * acos( cos( radians(TABLE1.latitude) )
* cos( radians( ADS.latitude ) )
* cos( radians( ADS.longitude )
- radians(TABLE1.longitude) )
+ sin( radians(TABLE1.latitude) )
* sin( radians( ADS.latitude ) ) ) )
AS check1,
( 6371 * acos( cos( radians(TABLE2.latitude) )
* cos( radians( ADS.latitude ) )
* cos( radians( ADS.longitude )
- radians(TABLE2.longitude) )
+ sin( radians(TABLE2.latitude) )
* sin( radians( ADS.latitude ) ) ) )
AS check2,
( 6371 * acos( cos( radians(TABLE3.latitude) )
* cos( radians( ADS.latitude ) )
* cos( radians( ADS.longitude )
- radians(TABLE3.longitude) )
+ sin( radians(TABLE3.latitude) )
* sin( radians( ADS.latitude ) ) ) )
AS check3,
( 6371 * acos( cos( radians(TABLE4.latitude) )
* cos( radians( ADS.latitude ) )
* cos( radians( ADS.longitude )
- radians(TABLE4.longitude) )
+ sin( radians(TABLE4.latitude) )
* sin( radians( ADS.latitude ) ) ) )
AS check4
FROM ADS
RIGHT OUTER JOIN TABLE1
ON TABLE1.user = ?
RIGHT OUTER JOIN TABLE2
ON TABLE2.user = ?
RIGHT OUTER JOIN TABLE3
ON TABLE3.user = ?
RIGHT OUTER JOIN TABLE4
ON TABLE4.user = ?
HAVING check1 < 10 OR check2 < 10 OR check3 < 10 OR check4 < 10
LIMIT 0,3
If user isn't unique in TABLE1 (or any of the TABLEn), then there's a potential to return multiple copies of the same row from ADS.
With the query the way it is, if the specified user isn't found in TABLE4, then the query won't return any rows. I suspect what you meant was a LEFT JOIN, with ADS as the driving table, but that's just a guess. We don't know what those tables contain, why are there four of them, etc.)
If there's a reason you are using a RIGHT JOIN, and if the query with one table is working for you...
and if there is a small number of rows in each of TABLE1, TABLE2, TABLE3, TABLE4 for a specified user...
You could concatenate the results of queries of those tables into single derived table, and then join to the derived table. As an example:
SELECT ADS.name, ADS.text,
( 6371 * acos( cos( radians(t.latitude) )
* cos( radians( ADS.latitude ) )
* cos( radians( ADS.longitude )
- radians(t.longitude) )
+ sin( radians(t.latitude) )
* sin( radians( ADS.latitude ) ) )
) AS check1
FROM ADS
RIGHT
JOIN ( SELECT TABLE1.latitude, TABLE1.longitude
FROM TABLE1 WHERE TABLE1.user = ?
UNION ALL
SELECT TABLE2.latitude, TABLE2.longitude
FROM TABLE2 WHERE TABLE2.user = ?
UNION ALL
SELECT TABLE3.latitude, TABLE3.longitude
FROM TABLE3 WHERE TABLE3.user = ?
UNION ALL
SELECT TABLE4.latitude, TABLE4.longitude
FROM TABLE4 WHERE TABLE4.user = ?
) t
HAVING check1 < 10
LIMIT 3
This was finaly what I needed:
$reponse = $bdd->prepare('
SELECT * FROM
(
SELECT ADS.id AS id, ADS.name, ADS.text,
( 6371 * acos( cos( radians(t.latitude) )
* cos( radians(ADS.latitude ) )
* cos( radians( ADS.longitude )
- radians(t.longitude) )
+ sin( radians(t.latitude) )
* sin( radians( ADS.latitude ) ) ) )
AS distance
FROM ADS
RIGHT
JOIN ( SELECT TABLE1.latitude, TABLE1.longitude
FROM TABLE1 WHERE TABLE1.user = :user
UNION ALL
SELECT TABLE2.latitude, TABLE2.longitude
FROM TABLE2 WHERE TABLE2.user = :user
UNION ALL
SELECT TABLE3.latitude, TABLE3.longitude
FROM TABLE3 WHERE TABLE3.user = :user
UNION ALL
SELECT TABLE4.latitude, TABLE4.longitude
FROM TABLE4 WHERE TABLE4.user = :user
) t
ON 1
HAVING distance < 10
) req GROUP BY id LIMIT 0,3
');
$reponse->execute(array('user' => $_SESSION['id']));

Sql query combining

i have two sql queries those are following
1) SELECT a.* FROM modzzz_listing_main as a LEFT JOIN modzzz_listing_rating as b ON a.id=b.gal_id WHERE LTRIM(a.city) = 'Houston' AND a.state = 'TX' AND a.tags LIKE '%Barber Shop%' ORDER BY b.gal_rating_sum DESC LIMIT 0 ,10
2) SELECT zip_code ,( 3959 * acos( cos( radians('41.97734070') ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians('-70.97234344') ) + sin( radians('41.97734070') ) * sin( radians( latitude ) ) ) ) AS distance FROM city_finder WHERE latitude IS NOT NULL AND longitude IS NOT NULL HAVING distance < 20 ORDER BY distance ASC
how can i combine this two queries by the condition `
modzzz_listing_main.zip=city_finder.zip_code
` .i am totally confused..please any one help me..
to see the join easier:
select * from
(
SELECT a.* FROM modzzz_listing_main as a LEFT JOIN modzzz_listing_rating as b ON a.id=b.gal_id WHERE LTRIM(a.city) = 'Houston' AND a.state = 'TX' AND a.tags LIKE '%Barber Shop%' ORDER BY b.gal_rating_sum DESC LIMIT 0 ,10
) queryA
left join
(
SELECT zip_code ,( 3959 * acos( cos( radians('41.97734070') ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians('-70.97234344') ) + sin( radians('41.97734070') ) * sin( radians( latitude ) ) ) ) AS distance FROM city_finder WHERE latitude IS NOT NULL AND longitude IS NOT NULL HAVING distance < 20 ORDER BY distance ASC
) queryB
on queryA.zip=queryB.zip_code
proper formatting
SELECT *
FROM
( SELECT a.*
FROM modzzz_listing_main AS a
LEFT JOIN modzzz_listing_rating AS b ON a.id=b.gal_id
WHERE LTRIM(a.city) = 'Houston'
AND a.state = 'TX'
AND a.tags LIKE '%Barber Shop%'
ORDER BY b.gal_rating_sum DESC LIMIT 0 ,
10 ) queryA
LEFT JOIN
( SELECT zip_code ,
(3959 * acos(cos(radians('41.97734070')) * cos(radians(latitude)) * cos(radians(longitude) - radians('-70.97234344')) + sin(radians('41.97734070')) * sin(radians(latitude)))) AS distance
FROM city_finder
WHERE latitude IS NOT NULL
AND longitude IS NOT NULL HAVING distance < 20
ORDER BY distance ASC ) queryB ON queryA.zip=queryB.zip_code

Distinct not working properly

I've wrote a query with DISTINCT but I still get duplicate records returned.
SELECT DISTINCT
`cuisine_types`.`id`,
`cuisine_types`.`name`,
`cuisine_types`.`image`,
(
SELECT group_concat(`tagname` separator ', ')
FROM `cuisine_tags`
WHERE `cuisine_type` = `cuisine_types`.`id`
) AS tags,
(
3959 * acos( cos( radians(" . $dLat . ") ) * cos( radians( gps_lat ) ) * cos( radians( gps_lon ) - radians(" . $dLon . ") ) + sin( radians(" . $dLat . ") ) * sin( radians( gps_lat ) ) )
) AS distance
FROM `company`
LEFT JOIN `cuisine_types`
ON
`company`.`cuisine_type_id` = `cuisine_types`.`id`
HAVING
distance < " .$dMiles
When I try using the GROUP BY function my query isn't working properly.
When I use GROUP BY I place it above my HAVING:
GROUP BY `cuisine_types`.`name`
Examples:
When I use it with these values:
$dLat = '52.779716';
$dLon = '21.84803';
$iKm = '30';
It returns:
id = 1
name = Snackbar
image =
tags = Patat, Snacks
distance = 17.4713944772963
When I use $iKm with 3000 it returns this row as well:
id = 1
name = Snackbar
image =
tags = Patat, Snacks
distance = 722.407714147792
So I get two records.
When I use this with groupby and $iKm = 30; It returns nothing. With a value of 3000 it returns one row. But I have one record with a distance of 17 miles so thats below 30.
This should fix your problem, the issue was the distance calculation blocked the GROUP BY function. By putting the equation in the HAVING itself, the problem seemed to be fixed. Sorry I can't explain it in more detail.
SELECT
`cuisine_types`.`name`,
`cuisine_types`.`id`,
`cuisine_types`.`image`
`c`.`gps_lat` as lat,
`c`.`gps_lon` as lon,
(SELECT group_concat(`tagname` separator ', ') FROM `cuisine_tags` WHERE `cuisine_type`=`cuisine_types`.`id`) as tags FROM `company` as c LEFT JOIN `cuisine_types` ON c.`cuisine_type_id`
= `cuisine_types`.`id` GROUP BY `cuisine_types`.`name` HAVING ( 3959 * acos( cos( radians(52.779716) ) * cos( radians( lat ) ) * cos( radians( lon ) - radians(21.84803) ) + sin( radians(52.779716) ) * sin( radians( lat ) ) ) ) < 2000;