Query returning Unexpected values - mysql

SELECT *
FROM workshop_planning_history
WHERE STATUS =1
OR STATUS =2
AND start_date =2015 -11 -29
OR end_date <=2016 -01 -10
OR end_date >=2016 -01 -10
I am running the above query and i am expecting values from Workshop_planning_history whose status is either 1 or 2 but i am getting results which have a status of 3 along with the rows having status 1 & 2.
What's wrong with my query please Help ...

You have to add some parenthesis to the predicate, because the precedence of operators is NOT AND OR, so your query is interpreted as:
SELECT *
FROM workshop_planning_history
WHERE STATUS = 1
OR (STATUS = 2 AND start_date = '2015-11-29')
OR end_date <= '2016-01-10'
OR end_date >= '2016-01-10'
Change to:
SELECT *
FROM workshop_planning_history
WHERE (STATUS = 1 OR STATUS = 2)
AND (start_date = '2015-11-29'
OR end_date <= '2016-01-10'
OR end_date >= '2016-01-10')
Or something that is proper according to your logic.

The right way to do it would be using the in clause for status.
Documentation: Here
SELECT *
FROM workshop_planning_history
WHERE STATUS in (1,2)
AND start_date =2015 -11 -29
Also why use end_date if you use both <= & >= operators?

You need to add parentesis in between AND condition of status and date comparison also its good idea to use date modifier when comparing dates
SELECT *
FROM workshop_planning_history
WHERE (STATUS =1
OR STATUS =2)
AND (date(start_date) = date '2015 -11 -29'
OR date(end_date) <=date '2016 -01 -10'
OR date(end_date) >=date '2016 -01 -10')

Related

How should I use NOT IN statement in MySQL

I am trying to use NOT IN statement with MySQL. However, I get 0 row with code below (no syntax error). I am sure there should be more than 0 row with the statement. What syntax should I adjust?
SELECT DISTINCT member_id
FROM client_payments
INNER JOIN client_purchase_records ON client_purchase_records.id = client_payments.purchase_record_id
WHERE status = 1
AND client_payments.created_at > '2021-10-28 00:00:00'
AND client_payments.created_at < '2021-10-31 23:59:00'
NOT IN(
SELECT DISTINCT member_id
FROM client_payments
INNER JOIN client_purchase_records ON client_purchase_records.id = client_payments.purchase_record_id
WHERE status = 1
AND client_payments.created_at > '2020-9-30 00:00:00'
AND client_payments.created_at < '2021-10-27 23:59:00'
);
Difference about two query is mainly about created_at column, I want to do "set difference operation" with period A(2021-10-28 00:00:00 - 2021-10-31 23:59:00 )and period B(2020-9-30 00:00:00 - 2021-10-27 23:59:00)
I want to query out member_id who pay during 2020-9-30 00:00:00 - 2021-10-27 23:59:00
Subtract with member_id who pay during 2021-10-28 00:00:00 - 2021-10-31 23:59:00
Finally I get member_id who pay during 2021-10-28 00:00:00 - 2021-10-31 but not pay during 2020-9-30 00:00:00 - 2021-10-27 23:59:00 ( new member_id never show before)
no syntax error
The error is in the logic.
Your condition, after adding the parenthesis according to operators priority, looks like
AND ( (client_payments.created_at < '2021-10-31 23:59:00') NOT IN ( {subquery} ) )
I.e. the result of comparing client_payments.created_at < '2021-10-31 23:59:00' (which is 0, 1 or NULL) is searching in the subquery output which is obviously illogical.
You presumably want to be saying AND member_id NOT IN (...your subquery...); as is, it is using the previous condition instead of member_id.
Also, it looks like you want >= and <=, not > and <.
I would do this like so instead:
SELECT member_id
FROM client_payments
INNER JOIN client_purchase_records ON client_purchase_records.id = client_payments.purchase_record_id
WHERE status = 1
AND client_payments.created_at >= '2021-09-30 00:00:00'
AND client_payments.created_at <= '2021-10-31 23:59:00'
GROUP BY member_id
HAVING MIN(client_payments.created_at) >= '2021-10-28 00:00:00'

MySQL TIME() BETWEEN datetime issue

I'm trying to find to which shift belongs a datetime field.
Shifts are defines as time, and I have a startingHour and endingHour.
The query
SELECT * FROM shifts WHERE TIME('2009-11-20 06:35:00') BETWEEN '06:00:00' and '19:00:00'
works perfect, but when the shift is set to start 19:00:00 to 06:00:00 and the time is 23:35:00 it doesn't return anything
WHERE TIME('2009-11-20 23:35:00') BETWEEN '19:00:00' and '06:00:00'
that line isn't returning anything though I do have records on the table
Thanks
That's the shifts table.
if I query this:
SELECT
a.ID,
b.Nombre
FROM turnos a
JOIN operarios b ON a.oID = b.oId
WHERE a.uId = 1
AND (TIME('2019-11-22 18:23:00') BETWEEN a.horaInicio AND a.horaFin )
LIMIT 1
I get the proper result, but when I query this:
SELECT
a.ID,
b.Nombre
FROM turnos a
JOIN operarios b ON a.oID = b.oId
WHERE a.uId = 1
AND (TIME('2019-11-22 02:45:00') BETWEEN a.horaInicio AND a.horaFin )
LIMIT 1
I get no result.
These are two cases: start time < end time and start time > end time. You need something like this:
where (start_time < end_time and $t >= start_time and $t < end_time)
or (start_time >= end_time and ($t < start_time or $t >= end_time))
Since '19:00:00' is greater than '06:00:00' then:
BETWEEN '19:00:00' and '06:00:00'
returns 0 (false) and you get no rows.
One way to get the results that you want is to use CASE like this:
.................
AND 1 = CASE
WHEN a.horaInicio <= a.horaFin THEN TIME('2019-11-22 02:45:00') BETWEEN a.horaInicio AND a.horaFin
ELSE (TIME('2019-11-22 02:45:00') BETWEEN a.horaInicio AND '23:59:59')
OR (TIME('2019-11-22 02:45:00') BETWEEN '00:00:00' AND a.horaFin)
END

SQL Select rows comparing a datetime field that could be null

Let's guess we've got the following table:
- id (int)
- active (int)
- active_from (datetime) (NULL)
- active_until (datetime) (NULL)
Now, what I want to get is all the active records. An active record implies:
- active = 1
- active_from <= current_date (IF IT'S NOT NULL)
- active_until >= current_date (IF IT'S NOT NULL)
I'm looking for a query that applies these 3 requirements in one single query. I'm currently using:
SELECT * FROM product WHERE active = 1 AND active_from <= NOW() AND active_until >= NOW();
I will only get the behavior I want with rows that don't have NULL active_from or active_until.
Note: I know it would be more appropiate to compare the current date after storing it in a variable (posing it this way because I'm filling it with PHP parameters).
Thank you in advance.
SELECT * FROM YourTableName
WHERE active = 1
AND (active_from < CURDATE()
OR active_from IS NULL)
AND (active_until > CURDATE()
OR active_until IS NULL);
Use ifnull in your query (encase active_from and active_until in it):
https://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html#function_ifnull
So, basically, if the value is null, use another date instead. Which date is up to you and the specific business logic you need (ex: 2100-01-01 or 1900-01-01 etc.)
SELECT * FROM product
WHERE active = 1
AND (active_from < CURDATE()
AND active_from IS NOT NULL)
AND (active_until > CURDATE()
AND active_until IS NOT NULL)

Calculate difference between first and last result

I have got a table with two columns. The first one ("val") is a integer, the second a timestamp ("ts").
Now I want to calculate the difference between the first and the last value of a given timespan.
SELECT MAX(val) - MIN(val) AS difference WHERE ts >= '2015-01-01 00:00:00' AND ts <= '2015-01-07 23:59:59'
This one is not sufficient, because in the course of time the values can exceed/undercut the first and the last value.
Example:
Day 1: 100
Day 2: 120
Day 3: 110
Day 4: 98
Day 5: 105
Day 6: 112
Day 7: 110
The difference is 110 (Day 7) minus 100 (Day 1) = 10. Not Max(val) = 120 minus Min(val) = 98 = 22
Thanks!
Join to a subquery that returns the first and last dates and join using those, and use some simple arithmetic to calculate the difference using sum():
select sum(val * case ts when ts1 then -1 else 1 end) diff
from data
join (select min(ts) ts1, max(ts) ts2
from data
where ts between ? and ?) x
on ts in (ts1, ts2)
See demo (demo schema has been simplified to isolate the essence of the solution).
One method is to use two subqueries, one that gets the first value and one that gets the last value:
SELECT ((SELECT val
FROM table t
WHERE ts >= '2015-01-01 00:00:00' AND ts <= '2015-01-07 23:59:59'
ORDER BY val DESC
LIMIT 1
) -
(SELECT val
FROM table t
WHERE ts >= '2015-01-01 00:00:00' AND ts <= '2015-01-07 23:59:59'
ORDER BY val ASC
LIMIT 1
)
) as difference

using 'AND' with COUNT(*)

I would like to get the total number of entries, upon 2 or more conditions.
Yet is seems as if mysql is ignoring the 'AND' clause in the query.
edit:
I want to get number of calls made by user with id=97, while the date is between starttime and stoptime, and prefix is like *us*
Example:
select count(*)
from calls
where id = 97
and starttime >= '2012-06-11'
and stoptime >= '2012-06-12'
and prefix like '%us%'
This gives me total amount of calls from id=97, while ignoring the rest of the conditions
I'm guessing that you want the second condition on the date should be <=:
select count(*)
from calls
where id = 97
and starttime >= '2012-06-11'
and stoptime <= '2012-06-12'
and prefix like '%us%';
You should also know that if you are storing times in the date time field along with the date, the you might really want:
select count(*)
from calls
where id = 97
and date(starttime) >= '2012-06-11'
and date(stoptime) <= '2012-06-12'
and prefix like '%us%';
or better yet:
select count(*)
from calls
where id = 97
and starttime >= '2012-06-11'
and stoptime <= '2012-06-13'
and prefix like '%us%';
I think you meant to do something like
select count(*)
from calls
where id = 97
and (starttime >= '2012-06-11' and stoptime <= '2012-06-12')
and prefix like '%us%'