Mysql Coalesce treats field differently than where - mysql

I got a strange condition in Mysql coalesce function:
select start_date, end_date, COALESCE(end_date, start_date)
from log where log_id = 8999134
returns: 2011-02-09 23:00:38, NULL, NULL
Anyone has any idea why coalsce is not working as it should ?
Edit:
After some research I decided to try the query in MYSQL workbench and saw that the tool I was using to access the database was incorrectly returning null when the field had end_date = 0000-00-00 00:00:00.
Yet the problem got even more strange. The result above is already a debug. The first query was:
select id, start_date, COALESCE(end_date, start_date)
from log where end_date is null
from where I debugged:
select id, start_date, end_date, end_date is null
from log where end_date is null
and the result was: 2011-02-09 23:00:38, 0000-00-00 00:00:00, 0
This is result's first line, but got equal results to the other lines. Why the end_date is NULL for where and not to coalesce ?
the datatype for both fields is datetime

This would occur if the value NULL were really a string 'NULL'. This would suggest that fields that should be dates are really being stored as strings.
Check the data types. If they are varchar() or char(), then this is probably the problem. Then, fix the problem by fixing the data structure. Date/times should be stored using native database formats.
EDIT:
A date value of 0 is not the same as NULL.

if you have your dates stored like that 0000-00-00 00:00:00 then Coalesce will not work because its not NULL . try this with CASE :
select id, start_date, CASE WHEN end_date = '0000-00-00 00:00:00'
THEN start_date
ELSE end_date END as coalesced_date
from log where log_id = 8999134
Or this:
SELECT id, start_date,
CASE WHEN end_date ='0000-00-00 00:00:00' AND start_date != '0000-00-00 00:00:00'
THEN start_date
WHEN start_date ='0000-00-00 00:00:00' AND end_date != '0000-00-00 00:00:00'
THEN end_date
WHEN start_date ='0000-00-00 00:00:00' AND end_date = '0000-00-00 00:00:00'
THEN 'They are nulled'
ELSE end_date END as coalesced_date
FROM log
WHERE log_id = 8999134
EDIT2:
you dont need to use NULL in your where clause since you dont have null values , you have '0000-00-00 00:00:00' and this is not null.
so instead of
where end_date is null
use
where end_date != '0000-00-00 00:00:00'

Related

Search for a single date in a DATETIME or TIMESTAMP column

I have a problem retrieving data from a table between two dates.
Everything works as it should when two dates differ from each other, but when I want to search for all records from today, it searche nothing:
SELECT * from exampletable where created_date >= '2022-10-28' AND created_date<= '2022-10-28'
To get all records for a single day using a TIMESTAMP or DATETIME type column you have these options:
WHERE DATE(created_date) = '2022-10-28'
However - Wrapping a column into a function you will loose the ability to use an index.
Other ways which can use an index:
WHERE created_date BETWEEN '2022-10-28 00:00:00' AND '2022-10-28 23:59:59'
WHERE created_date >= '2022-10-28'
AND created_date < '2022-10-29'
WHERE created_date >= '2022-10-28'
AND created_date < '2022-10-28' + INTERVAL 1 DAY
Your query
where created_date >= '2022-10-28' AND created_date <= '2022-10-28'
is equivalent with
where created_date = '2022-10-28'
If created_date is of type DATETIME or TIMESTAMP it is the same as
where created_date = '2022-10-28 00:00:00'
and the query would only return records with the exact time of 00:00:00.

Select highest date if not zero

I have the following table:
Mails
id (int 11 auto increment)
user_id (int 11)
subject (varchar 255)
body (text)
deleted (datetime)
By default the deleted column holds the value 0000-00-00 00:00:00 When something gets deleted the deleted column will be set to the delete date. e.g.: 2017-08-14 09:37:13
Now I want to query this table and get either the user_id record where deleted = 0000-00-00 00:00:00 or the most recent deleted value if there is no user record where deleted = 0000-00-00 00:00:00
You can sort a specific value on top with a case:
select user_id
from YourTable
order by
case
when deleted = '0000-00-00 00:00:00' then '9999-12-31 23:59:59'
else deleted
end desc
limit 1
Where '9999-12-31 23:59:59' is the maximum value of a datetime.
For multiple users, you could look up the maximum with a join:
select *
from Mails m1
join (
select user_id
, max(
case
when deleted = '0000-00-00 00:00:00' then '9999-12-31 23:59:59'
else deleted
end) max_deleted
from Mails
group by
user_ud
) m2
on m1.user_id = m2.user_id
and case
when m1.deleted = '0000-00-00 00:00:00' then '9999-12-31 23:59:59'
else m1.deleted
end = m2.max_deleted
Making a slight amendment to Andomar's answer to remove the limit you could try something like:
SELECT user_id
FROM YourTable
WHERE
case
when deleted = '0000-00-00 00:00:00' then 'true'
else deleted then 'true'
end desc = 'true'
As Case statements run sequentially this would try and return true for the filter in the WHERE clause if the deleted date is '0000-00-00 00:00:00' and if this holds false it will move to the next case which always holds try and passes the filter.
Not the prettiest though.

WHERE returning too many rows for data NOT BETWEEN two dates

I want to return data that is not between current date and the last 7 days.
My SELECT statement appears ok, but it is also returning the current day's data.
SELECT
customer.id AS id,
customer.customer_id AS customer_id,
customer.name AS name,
customer.phone1 AS phone1,
customer.location_area AS location_area,
sales.post_date AS post_date
FROM
sales
INNER JOIN
customer
ON
sales.customer_id = customer.customer_id
WHERE
post_date
NOT BETWEEN
CAST( DATE_SUB(NOW(), INTERVAL 7 DAY) AS DATE )
AND
CAST( NOW() AS DATE )
ORDER BY
sales.id
DESC
LIMIT 30
Please note the customer_id field used in the ON clause is not a primary key in any of the two referenced tables.
What might be missing in my query?
This problem is usually confusion about the different meanings of DATE datatypes on the one hand and TIMESTAMP or DATETIME data types on the other.
Let's say NOW() is 1-April-2017 09:35. And, let's say you have a row in your sales table with a post_date value of 1-April-2017 08:20. Let's say your post_date column has the data type DATETIME.
Then your WHERE clause looks like this after values are applied.
WHERE '2017-04-01 08:20' NOT BETWEEN CAST( '2017-03-25 09:35' AS DATE )
AND CAST( '2017-04-01 09:35' AS DATE )
Applying the CAST operations, we get.
WHERE '2017-04-01 08:20' NOT BETWEEN '2017-03-25'
AND '2017-04-01'
Finally, when comparing a DATETIME or TIMESTAMP to a DATE value, the DATE value is interpreted as having a time of midnight. So your query looks like this:
WHERE '2017-04-01 08:20' NOT BETWEEN '2017-03-25 00:00:00'
AND '2017-04-01 00:00:00'
And, guess what? '2017-04-01 08:20' is after '2017-04-01 00:00:00'.
What you need is this:
WHERE
NOT (
post_date >= CURDATE() - INTERVAL 7 DAY --on or after midnight 2016-3-25
AND post_date < CURDATE() + INTERVAL 1 DAY --before midnight 2016-04-02
)
Please notice that this expression encompasses eight days total.
You can't use BETWEEN for this kind of comparison because you need < for the end of the range, and BETWEEN uses <= for the ends of all its ranges.
Also, CURDATE() is much easier to read than CAST(NOW() AS DATE).

MySQL Select MIN DateTime when DateTime is set to 0000-00-00 00:00:00

I have this MySQL Query that is ran that gets me a start date for a Gantt chart of Project Tasks I am building.
It works great as long as all my Project Tasks have a Start Date set, however Tasks that are not "started" yet have a start_date value of 0000-00-00 00:00:00 This result in my Gantt chart trying to build a chart with like 16,343 days
SELECT MIN( date_started ) AS start_date
FROM apoll_web_projects_tasks
WHERE project_id = '205e34c6-7381-92eb-e6ab-54125429cd2a'
Is there a way to get the value I want but disregarding any values of 0000-00-00 00:00:00 ?
Just add WHERE date_started != '0000-00-00 00:00:00' like this:
SELECT MIN( date_started ) AS start_date
FROM apoll_web_projects_tasks
WHERE project_id = '205e34c6-7381-92eb-e6ab-54125429cd2a'
AND date_started != '0000-00-00 00:00:00'

Get entries between one date and another via a unix timestamp

If I have a column in a table called creation_date in the database that contain unix timestamp values, how do I get results returned that were only created between for example May 10th 2013 and June 9th 2013?
I tried the below but all I got returned was 0; which isn't correct.
SELECT COUNT(*) FROM my_table WHERE FROM_UNIXTIME(creation_date) BETWEEN '05-10-2013 00:00:00' AND '06-09-2013 23:59:59';
1) If creation_date is a timestamp stored as TIMESTAMP:
SELECT
COUNT(*)
FROM
my_table
WHERE
creation_date
BETWEEN '2013-05-10 00:00:00'
AND '2013-06-09 23:59:59';
2) If creation_date is a timestamp stored as INT:
SELECT
COUNT(*)
FROM
my_table
WHERE
creation_date
BETWEEN UNIX_TIMESTAMP('2013-05-10 00:00:00')
AND UNIX_TIMESTAMP('2013-06-09 23:59:59');