Cannot spot the difference between these two queries - mysql

Trying to clean up a long query I have come up with a modified version, but now the old query with certain parameters returns 6 rows, but my version returns none. I have been straining my eyes to spot the difference but cannot find any. Here are the WHERE clauses from the two versions with identical set of parameters:
The ugly (but working) version:
SELECT ...
FROM table as a
WHERE 1=1
and a.title LIKE '%Manager%'
and a.status='Approved'
and (a.effected_date<=now())
and (
(DATE_ADD(a.effected_date, INTERVAL 30 DAY) >= now() AND a.is_hotjob=0)
or
(DATE_ADD(a.effected_date, INTERVAL 30 DAY) >= now() AND a.is_hotjob=1)
)
My cleaned (but broken) version:
SELECT ...
FROM `table` AS `a`
WHERE CONCAT(`a`.`title`, ' | ', `a`.`job_detail_section`) LIKE '%Manager%' AND
`a`.`status` = 'Approved' AND
`a`.`effected_date` <= '2013-12-30' AND
(`a`.`effected_date` >= '2013-11-30' OR `a`.`is_hotjob` = '1')

You got the last AND/OR backwards:
`a`.`effected_date` <= '2013-12-30' OR
(`a`.`effected_date` >= '2013-11-30' AND `a`.`is_hotjob` = '1')
EDIT: after reformatting, the answer looks more like:
SELECT ...
FROM `table` AS `a`
WHERE CONCAT(`a`.`title`, ' | ', `a`.`job_detail_section`) LIKE '%Manager%' AND
`a`.`status` = 'Approved' AND
`a`.`effected_date` <= now() AND
`a`.`effected_date` >= DATE_ADD(a.effected_date, INTERVAL 30 DAY)
and POSSIBLY:
AND `a`.`is_hotjob` IN (0,1)

As a substitute of-
(DATE_ADD(a.effected_date, INTERVAL 30 DAY) >= now() AND a.is_hotjob=0)
or
(DATE_ADD(a.effected_date, INTERVAL 30 DAY) >= now() AND a.is_hotjob=1)
You could use the following-
(`a`.`effected_date` >= '2013-11-30' AND `a`.`is_hotjob` in (0, 1))
But according to the additional info i.e. a.is_hotjob has value either 0 or 1 then there is no need to mention it in the condition at all. So basically the following format will be sufficient-
`a`.`effected_date` >= '2013-11-30'

Related

How do I subtract two results from a SELECT statement within that statement?

This pulls back two int values of yesterday and today. I'd like to subtract the two results from within the statement in a third column called difference:
SELECT (
SELECT COUNT(*)
FROM collectors_users
WHERE DATE(dateadded) = CURDATE() - INTERVAL 1 DAY
) AS yesterday, COUNT(*) AS today
FROM collectors_users
WHERE DATE(dateadded) = CURDATE()
You need to repeat the expressions. SQL (in general) does not allow you to re-use column aliases in the same SELECT. You can simplify the logic to:
SELECT SUM(DATE(dateadded) = CURDATE() - INTERVAL 1 DAY) AS yesterday,
SUM(DATE(dateadded) = CURDATE()) as today,
(SUM(DATE(dateadded) = CURDATE()) -
SUM(DATE(dateadded) = CURDATE() - INTERVAL 1 DAY)
) as diff
FROM collectors_users
WHERE dateadded >= CURDATE() - INTERVAL 1 DAY AND
dateadded < CURDATE() + INTERVAL 1 DAY;
Note that the logic for the WHERE clause covers two days. Also, it does not use DATE(). This would allow the query to use an index, if available.

Error in SQL CASE in where statement during select

I have a query that selects 3 random items from database table but I need to apply some more logic to the query based on the value of a field in the query.
This is what I have so far hope it makes sense. Have not fully tested it yet figured I would run it through you guys first see if there is anything that jumps out.
SELECT ord.id, keyword, url, daily_max
FROM orders AS ord
LEFT JOIN product_tasks AS tsk ON tsk.id = ord.task_id
LEFT JOIN product_groups AS grp ON grp.id = tsk.product_group
WHERE (
status = 'approved' AND
ord.total_actions_today < tsk.daily_max AND
grp.id = 1 AND
country_code = '$country' AND
(
CASE WHEN daily_max >= 5 THEN last_displayed < (NOW() - INTERVAL 30 MINUTE)
CASE WHEN daily_max >10 THEN last_displayed < (NOW() - INTERAVAL 5 MINUTE)
ELSE last_displayed < (NOW() - INTERAVAL 60 MINUTE)
)
)
GROUP BY ord.id
ORDER BY RAND()
LIMIT 3
Just tested the query and as I suspected I have my syntax wrong so any help would be appreciated:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CASE WHEN daily_max >10 THEN last_displayed < (NOW() - INTERAVAL 5 MINUTE) ' at line 14
Edit - Fixed
(After several attempts + edits):
SELECT ord.id, keyword, url, daily_max
FROM orders AS ord
LEFT JOIN product_tasks AS tsk ON tsk.id = ord.task_id
LEFT JOIN product_groups AS grp ON grp.id = tsk.product_group
WHERE (
status = 'approved' AND
ord.total_actions_today < tsk.daily_max AND
grp.id = 1 AND
country_code = 'us'
AND last_displayed <
CASE WHEN (daily_max >= 5) THEN (NOW() - INTERVAL 30 MINUTE)
WHEN (daily_max >10) THEN (NOW() - INTERVAL 5 MINUTE)
ELSE (NOW() - INTERVAL 60 MINUTE)
END
)
GROUP BY ord.id
ORDER BY RAND()
LIMIT 3
http://sqlfiddle.com/#!2/ac4499/1
Solved DOH missing ) in the where statement
Move the last_displayed out of the CASE, such that it is compared to a single value as projected out of the CASE statement:
WHERE...
AND last_displayed <
CASE WHEN (daily_max >= 5) THEN (NOW() - INTERVAL 30 MINUTE)
WHEN (daily_max >10) THEN (NOW() - INTERVAL 5 MINUTE)
ELSE (NOW() - INTERVAL 60 MINUTE)
END;
Also note a couple of typos - INTERVAL not INTERAVAL, and just one CASE is required.
SqlFiddle here
Your structure of your WHERE was not correct. Try the following:
SELECT ord.id, keyword, url, daily_max
FROM orders AS ord
LEFT JOIN product_tasks AS tsk ON tsk.id = ord.task_id
LEFT JOIN product_groups AS grp ON grp.id = tsk.product_group
WHERE (
status = 'approved' AND
ord.total_actions_today < tsk.daily_max AND
grp.id = 1 AND
country_code = '$country' AND
(
CASE WHEN daily_max >10 THEN (NOW() - INTERAVAL 5 MINUTE)
WHEN daily_max >= 5 THEN (NOW() - INTERVAL 30 MINUTE)
ELSE (NOW() - INTERAVAL 60 MINUTE)
END > last_displayed
)
)
GROUP BY ord.id
ORDER BY RAND()
LIMIT 3

Applying a WHERE after CASE statement?

I'm using a CASE statement to build my query for some dates filtering, but after getting the proper CASE syntax, I can't manage to a apply a WHERE statement.
So, I was wondering, how may I do so?
My actual code is:
SELECT id, fecha_inicio,
CASE WHEN eventos.fecha_fin IS NULL
THEN DATE_ADD(eventos.fecha_inicio, INTERVAL 45 DAY)
ELSE fecha_fin
END as fecha_fin_new
FROM eventos
WHERE DATE_FORMAT(fecha_fin_new, '%Y-%m') >= '2006-01'
WHERE can only be used with table values. To process SELECT aliases you have to use HAVING.
SELECT id, fecha_inicio,
CASE WHEN eventos.fecha_fin IS NULL
THEN DATE_ADD(eventos.fecha_inicio, INTERVAL 45 DAY)
ELSE fecha_fin
END as fecha_fin_new
FROM eventos
HAVING DATE_FORMAT(fecha_fin_new, '%Y-%m') >= '2006-01'
You can also replace your CASE expression with:
IFNULL(fecha_fin, DATE_ADD(eventos.fecha_inicio, INTERVAL 45 DAY))
You don't need - and it's not efficient - to do this conversion to apply a WHERE or HAVING condition. You can alter the condition to work on table columns:
WHERE ( eventos.fecha_fin IS NULL
AND DATE_ADD(eventos.fecha_inicio, INTERVAL 45 DAY) >= '2006-01-01'
)
OR ( eventos.fecha_fin IS NOT NULL
AND fecha_fin >= '2006-01-01'
)
which can be further simplified/rewritten to:
WHERE eventos.fecha_fin IS NULL
AND eventos.fecha_inicio >= DATE_SUB('2006-01-01', INTERVAL 45 DAY)
OR eventos.fecha_fin >= '2006-01-01'
So, the query can be written as:
SELECT e.id, e.fecha_inicio,
COALESCE( e.fecha_fin, DATE_ADD(e.fecha_inicio, INTERVAL 45 DAY) )
AS fecha_fin_new
FROM eventos AS e
WHERE e.fecha_fin IS NULL
AND e.fecha_inicio >= DATE_SUB('2006-01-01', INTERVAL 45 DAY)
OR e.fecha_fin >= '2006-01-01'
This way:
the e.fecha_fin IS NULL AND ... OR ... condition is checked first and if there indexes that can be used for this condition, the query will be efficient. All other calculations are performed on the selected rows.
the computed column - whether with CASE, IFNULL() or CALESCE() doesn't matter - is not calculated for all rows of the table, only for the selected ones.
the DATE_FORMAT() function is not needed to be applied, not once.

Select rows with certain combination

First of all let me give you guys the SQLFiddle: http://sqlfiddle.com/#!2/1d8bd/11
I've been working on this for a while and am facing some programmers (and writers) block.
This is a sample pseudo code of what I am trying to accomplish in MySQL:
Return all rows WHERE {
(`to_user_id` = '27' AND `to_delete` >= SUBDATE(NOW(), INTERVAL 720 HOUR) )
AND
(`from_user_id` = '27' AND `from_delete` >= SUBDATE(NOW(), INTERVAL 720 HOUR) )
}
Are you looking for this (using OR instead of AND between groups of conditions)?
SELECT *
FROM messages
WHERE (to_user_id = 27 AND `to_delete` >= NOW() - INTERVAL 720 HOUR)
OR (from_user_id = 27 AND `from_delete` >= NOW() - INTERVAL 720 HOUR)
Here is SQLFiddle demo
One issue you're having is your to_delete and from_delete fields are both NULL in your Fiddle example. Therefore, they can never meet your WHERE criteria.
That apart, no need for parentheses if all of your operators are AND. Perhaps you're looking for OR instead?

MySQL - Select all UNLESS query

I have a query that I use the works, but now I need to modify it so that it excludes rows if they have a certain data in a field.
Here's the current code:
SELECT oc_ieentry,oc_sysitem,oc_item,oc_itemdesc,oc_purchasedate,oc_url
FROM catalog
WHERE oc_purchasedate >= date_sub(current_date, interval 21 day)
ORDER BY oc_item ASC
What I need to do is add a statement in there that if oc_ieentry LIKE 1, then those rows should not be shown.
Try this:
SELECT
oc_ieentry,oc_sysitem,oc_item,oc_itemdesc,oc_purchasedate,oc_url
FROM catalog
WHERE (oc_purchasedate >= date_sub(current_date, interval 21 day))
AND (oc_ieentry NOT LIKE 1)
ORDER BY oc_item ASC
You could add another condition in the WHERE clause, such as:
SELECT oc_ieentry,oc_sysitem,oc_item,oc_itemdesc,oc_purchasedate,oc_url
FROM catalog
WHERE
oc_purchasedate >= date_sub(current_date, interval 21 day)
AND oc_ieentry != 1
ORDER BY oc_item ASC
Add an extra condition to your WHERE?
...
WHERE oc_purchasedate >= date_sub(current_date, interval 21 day) AND oc_ieentry <> 1
...
You can use the NOT keyword in the WHERE clause:
SELECT * from products WHERE prod_price NOT IN (49, 100, 999);
Does it help you?