Reputation: 12856
I'm new to sub-queries and think I need them in the following situation, but am not sure how to proceed.
I have the following query. Now, I have two things I need to add to the query =
In FL, MD, NH, and WA currently insured can be 0 (boolean), while in the other states it should only be 1.
SELECT Count(*),
Avg(sl.our_cost),
Avg(sl.purchase_price)
FROM sold_leads AS sl
INNER JOIN leads AS l
ON l.id = sl.lead_id
INNER JOIN contacts AS c
ON c.lead_id = l.id
INNER JOIN drivers AS d
ON d.lead_id = l.id
WHERE c.state IN( 'AK', 'AL', 'AR', 'AZ',
'CA', 'CO', 'CT', 'DC',
'DE', 'FL', 'GA', 'HI',
'IA', 'ID', 'IL', 'IN',
'KS', 'KY', 'LA', 'MD',
'ME', 'MI', 'MN', 'MO',
'MS', 'MT', 'NC', 'ND',
'NE', 'NH', 'NJ', 'NM',
'NV', 'NY', 'OH', 'OK',
'OR', 'PA', 'RI', 'SC',
'SD', 'TN', 'TX', 'UT',
'VA', 'VT', 'WA', 'WI',
'WV', 'WY' )
AND l.leg = 0
AND ( Datediff(CURRENT_DATE, d.date_of_birth) / 365 ) >= 50
AND l.create_date >= '2012-1-1';
How would I go about adding these subqueries to my query? Is there a better method to find that information?
EDIT:
I should mention that it should have read 1 'car accident' or 'violation'. I have two different tables with car accidents and violations, and so for CA residents, I need only those who have 1 accident OR 1 violation.
Upvotes: 2
Views: 72
Reputation: 76537
Because the data for car_accidents
, violations
is in separate tables, you need to join them using a left join
.
Hope this makes sense :-)
SELECT Count(*),
Avg(sl.our_cost),
Avg(sl.purchase_price)
FROM sold_leads AS sl
INNER JOIN leads AS l
ON l.id = sl.lead_id
INNER JOIN contacts AS c
ON c.lead_id = l.id
INNER JOIN drivers AS d
ON d.lead_id = l.id
LEFT JOIN
(SELECT ca1.driver_id, COUNT(*) AS cnt FROM car_accidents ca1 GROUP BY ca1.driver_id) ca
ON (c.state = 'CA' and ca.driver_id = d.id)
LEFT JOIN
(SELECT v1.driver_id, COUNT(*) AS cnt FROM violations v1 GROUP BY v1.driver_id) v
ON (c.state IN ('CA') and v.driver_id = d.id)
WHERE c.state IN( 'AK', 'AL', 'AR', 'AZ','CA', 'CO', 'CT', 'DC',
'DE', 'FL', 'GA', 'HI','IA', 'ID', 'IL', 'IN',
'KS', 'KY', 'LA', 'MD','ME', 'MI', 'MN', 'MO',
'MS', 'MT', 'NC', 'ND','NE', 'NH', 'NJ', 'NM',
'NV', 'NY', 'OH', 'OK','OR', 'PA', 'RI', 'SC',
'SD', 'TN', 'TX', 'UT','VA', 'VT', 'WA', 'WI',
'WV', 'WY' )
AND l.leg = 0
AND ( Datediff(CURRENT_DATE, d.date_of_birth) / 365 ) >= 50
AND l.create_date >= '2012-1-1'
AND IFNULL(v.cnt,0) < 2 AND ifnull(ca.cnt.0) < 2
AND (c.state IN ('FL','MD','NH','WA') OR c.IsInsured = 1)
note It would make much more sense to have the states in a separate table. That way you can put the terms and conditions in that table and use them in your join criteria.
Table state
-----------
id : varchar(2) primary key not null
country : varchar(45) not null
max_accidents : int null
max_violations : int null
must_be_insured : boolean not null
Then you can rewrite the query as:
SELECT Count(*),
Avg(sl.our_cost),
Avg(sl.purchase_price)
FROM sold_leads AS sl
INNER JOIN leads AS l
ON l.id = sl.lead_id
INNER JOIN contacts AS c
ON c.lead_id = l.id
INNER JOIN drivers AS d
ON d.lead_id = l.id
INNER JOIN state s ON (s.id = c.state)
LEFT JOIN
(SELECT ca1.driver_id, COUNT(*) AS cnt FROM car_accidents ca1 GROUP BY ca1.driver_id) ca
ON (s.max_accidents IS NOT NULL AND ca.driver_id = d.id)
LEFT JOIN
(SELECT v1.driver_id, COUNT(*) AS cnt FROM violations v1 GROUP BY v1.driver_id) v
ON (s.max_violations IS NOT NULL AND v.driver_id = d.id)
AND l.leg = 0
AND (Datediff(CURRENT_DATE, d.date_of_birth) / 365.25 ) >= 50
AND l.create_date >= '2012-1-1';
AND IFNULL(v.cnt,0) < 2 AND ifnull(ca.cnt.0) < 2
AND (s.must_be_insured = 0 OR c.IsInsured = 1)
Upvotes: 1
Reputation: 4804
I know it's not the same as subqueries, but I often solve this "subconditions" problem with a CASE statement. You can add one to the end of your WHERE clause:
WHERE c.state IN (...)
AND l.leg = 0
AND ( Datediff(CURRENT_DATE, d.date_of_birth) / 365 ) >= 50
AND l.create_date >= '2012-1-1'
AND CASE
# Identify cases where record should be excluded
WHEN c.state = 'CA' AND c.car_acc > 1 THEN 0
WHEN c.state NOT IN ('FL', 'MD', 'NH', 'WA') AND c.currently_insured = 1 THEN 0
ELSE 1
END = 1
Caveat: I don't know how this affects performance, compared to other filtering approaches.
Upvotes: 0