Is A Datetime Column's Value the Default One - mysql

I have a MySQL table and a column of type datetime. It's default value is something like 0000-00-00 00:00:00.
How do I check if a given row's value on this datetime column is the above by using native MySQL query functionality. E.g. without using "SELECT * FROM table WHERE my_date<>'0000-00-00 00:00:00'", because this leaves room for errors on different MySQL servers and configurations I believe.

SELECT * FROM table WHERE my_date <> 0
You can test it with
select cast('0000-00-00 00:00:00' as datetime) = 0
which returns true (and false for all other datetime values).

You could do something like "SELECT * FROM table WHERE my_date > '1970-01-01 00:00:00". 1/1/1970 is the commonly used epoch date.

Related

A more elegant way to get current year-month to insert in a 'where' clause

The table I'm querying from has this DateTime column.
created_time
2022-03-19T15:21:52+08:00
2022-03-19T13:10:22+08:00
2022-03-19T13:09:52+08:00
2022-03-19T13:02:47+08:00
2022-03-20T20:51:03+08:00
select extract(year_month from curtime())
Using extract (as above) doesn't work as it will get me: 202203.
SELECT created_time
FROM `freemark-prod-zohocrm`.patients p
where select extract(year_month from curtime())
Therefore the query above will not give me any result as my 'where' clause needs to specifically ask for '2022-03%' and not 202203.
SELECT created_time
FROM `freemark-prod-zohocrm`.patients p
where date_format(p.created_time, '%Y')=(select extract(year from curtime()))
and date_format(p.created_time, '%m')=(select extract(month from curtime()))
Therefore I am currently using the query above to obtain Year='2022' AND Month='03' which I feel doesn't look that nice and might cause me future problems.
I am wondering if there is a more elegant way to get the current 'Year-Month' (eg.'2022-03%') to use in my 'where' clause.
Thank you for your time.
LIKE Example db<>fiddle
Since the query is a simple YYYY-MM prefixed lookup, use LIKE DATE_FORMAT(NOW(), '%Y-%m-%%') as 2022-03-%. Functioning the same for either DATETIME or VARCHAR column data-types, and is by-far the fastest solution regardless of indexing.
SELECT p.created_time
FROM `freemark-prod-zohocrm`.patients p
WHERE p.created_time LIKE DATE_FORMAT(NOW(), '%Y-%m-%%');
Compare YEAR_MONTH Criteria db<>fiddle
To fix the issue with the original query not returning results, match the criteria column and value functions. However, as a function is called on the column value a full-table scan will be performed.
SELECT p.created_time
FROM `freemark-prod-zohocrm`.patients p
WHERE EXTRACT(YEAR_MONTH FROM p.created_time) = EXTRACT(YEAR_MONTH FROM NOW());
To prevent a full-table scan avoid altering column values in the criteria using DATE_FORMAT(created_time), EXTRACT(... FROM created_time) or other functions, which will cause MySQL to check all rows in the table to determine if the condition matches.
MySQL 5.5 and earlier db<>fiddle
Note: In MySQL 5.5 and earlier, extract(year_month from curtime()) or for any date specific Temporal Intervals will return NULL because curtime() returns the TIME portion as HH:MM:SS.The behavior appears to have changed in MySQL 5.6 and later, where EXTRACT() will apply to the current date when the date argument is supplied as a TIME data-type and failing when supplied as a time string literal.
However, an undesirable value will be returned when using a date + time interval such as DAY_MINUTE and the date portion of the value is omitted.
SELECT
curtime(), /* 19:07:40 */
extract(year_month from curtime()), /* NULL */
extract(day_minute from curtime()); /* 1907 */
To resolve the issue always use NOW(), otherwise in MySQL 5.5 and earlier curtime() should be replaced with CURDATE() or NOW() depending on the interval being used.
DATE Interpreted Example db<>fiddle
As DATE_FORMAT() returns a string literal, to prevent string comparison issues in MySQL such as '10' > '2' = false, enforce a DATE or DATETIME context.
When using DATE or DATETIME interpreted values (see explanation below) to retrieve the rows for an entire month, the following criteria values can be used to force the condition to process in the context of a DATE data-type
DATE(DATE_FORMAT(NOW(), '%Y-%m-01')) to get the first day of the current month as a DATE data-type
LAST_DAY(NOW()) + INTERVAL 1 DAY to get the the first day of the next month as a DATE data-type.
SELECT p.created_time
FROM `freemark-prod-zohocrm`.patients p
WHERE p.created_time >= DATE(DATE_FORMAT(NOW() ,'%Y-%m-01'))
AND p.created_time < LAST_DAY(NOW()) + INTERVAL 1 DAY;
LAST_DAY(NOW()) will return the date as 2022-03-31
+ INTERVAL 1 DAY will increment the date by one day to 2022-04-01
MySQL 5.6+ Results
CREATE TABLE patients_varchar (
`id` INTEGER NOT NULL PRIMARY KEY,
`created_time` VARCHAR(25),
INDEX(`created_time`)
);
INSERT INTO patients_varchar
(`id`, `created_time`)
VALUES
('1', '2022-02-19T15:21:52+08:00'), /* Added to verify range */
('2', '2022-03-19T15:21:52+08:00'),
('3', '2022-03-19T13:10:22+08:00'),
('4', '2022-03-19T13:09:52+08:00'),
('5', '2022-03-19T13:02:47+08:00'),
('6', '2022-03-20T20:51:03+08:00'),
('7', '2022-03-31T20:51:03+08:00'),
('8', '2022-04-20T20:51:03+08:00'); /* Added to verify range */
created_time
2022-03-19T13:02:47+08:00
2022-03-19T13:09:52+08:00
2022-03-19T13:10:22+08:00
2022-03-19T15:21:52+08:00
2022-03-20T20:51:03+08:00
2022-03-31T20:51:03+08:00
VARCHAR and Date Time Literals Explanation
When the column data-type is VARCHAR using a valid date time string literal format such as YYYY-MM-DDTHH:MM:SS+08:00, MySQL will automatically interpret the column value format of YYYY-MM-DDTHH:MM:SS+MM:HH as a DATETIME data-type appropriately when provided a criteria value in the DATE or DATETIME data-type context.Please see the String and Numeric Literals in Date and Time Context for more details.
DATETIME context and time zone offsets
For MySQL 5.6+ to specify the inclusion of a time value, use TIMESTAMP(DATE_FORMAT(LAST_DAY(NOW()), '%Y-%m-%d 23:59:59')) to force a DATETIME context as opposed to using DATE().
For MySQL 5.5 and earlier db<>fiddle, when specifying a DATETIME context, the time zone offset in the column value is not parsed correctly and produces a different result. Using a string context of DATE_FORMAT(LAST_DAY(NOW()), '%Y-%m-%dT23:59:59') resolves the issue but may produce unexpected results, due to the string context comparison eg: '10' > '2' = false.
Note: the T is required for MySQL to parse the YYYY-MM-DDTHH:MM:SS formatted column value correctly.
For example the following conditions will all return true due to the DATETIME context. While MySQL 8.0+ will process the time zone offset when it is included in the string.
SELECT
'2022-02-19T15:21:52+08:00' = TIMESTAMP('2022-02-19T15:21:52'),
'2022-02-19T15:21:52+08:00' < TIMESTAMP('2022-02-20T15:21:52'),
'2022-02-19T15:21:52+08:00' > TIMESTAMP('2022-02-18T15:21:52'),
'2022-02-19T00:00:00+08:00' = TIMESTAMP('2022-02-19'),
'2022-02-19T15:21:52+08:00' < TIMESTAMP('2022-02-20'),
'2022-02-19T15:21:52+08:00' > TIMESTAMP('2022-02-18');
As opposed to the following conditions comparing strings that all return unexpected results.
SELECT
'2022-02-19T15:21:52+08:00' = '2022-02-19T15:21:52', # false
'2022-02-19T15:21:52+08:00' <= '2022-02-19T15:21:52', # false
'2022-02-19T15:21:52+08:00' > '2022-02-19T15:21:52'; # true
querying based on function calls such as extract(), or others datepart(), etc. are not Sargeable
What you would be better doing is something like
where
created_time >= '2022-03-01'
AND created_time < '2022-04-01'
This way, it gets the entire month in question including time portion up to 2022-03-31 # 11:59:59pm.
Now, to compare automatically against whatever the current date IS, you can do with MySQL Variables to compute the first of the month and beginning of next month for your from/to range.
select
...
from
( select #FirstOfMonth := DATE_FORMAT(CURDATE(), '%Y-%m-01'),
#FirstOfNextMonth := date_add( #FirstOfMonth, interval 1 month )) sqlvars,
`freemark-prod-zohocrm`.patients p
where
p.created_time >= #FirstOfMonth
AND p.created_time < #FirstOfNextMonth

MySQL - How to select rows where datetime field is not equal to 0000-00-00 00:00:00?

Here is my table "tb_posts":
I want to select only those rows where datetime field i.e. post_date_published is not equal to 0000-00-00 00:00:00. I am using following query but it doesn't work:
SELECT * FROM `tb_posts` WHERE `post_date_published` IS NOT NULL
I am getting the same output as shown in the above picture.
Why IS NOT NULL is not working?
As per the MYSQL documentation it saves invalid dates as '0000-00-00 00:00:00'. It will not be considered as NULL.
Try comparing with the date '0000-00-00 00:00:00':
SELECT * FROM tb_posts where post_date_published != '0000-00-00 00:00:00'
A method I use with this sort of thing is
SELECT `columns` FROM `tb_posts` WHERE UNIX_TIMESTAMP(`post_date_published`) > 0
From the MySQL Documentation:
The valid range of argument values is the same as for the TIMESTAMP
data type: '1970-01-01 00:00:01.000000' UTC to '2038-01-19
03:14:07.999999' UTC. If you pass an out-of-range date to
UNIX_TIMESTAMP(), it returns 0.
The UNIX_TIMESTAMP function forces the result to be an integer so it's much easier to work with in these quick comparisons. It is also vital for working with MySQL 5.7 where "empty" (ie zero value) date/time columns are not allowed.
(I had a lot of grief trying to convert various date columns to NULL because MySQL 5.7+ didn't recognise 0000-00-00 00:00:00 as a valid comparison -- so I converted it to a unix timestamp so as to compare the timestamp rather than the actual [invalid] date.)

Want to run a query which gives me results between two dates. I have timestamp in unix epoch format

I have got timestamps in epoch UNIX format. I want to run a query by directly giving date and not timestamp. How is that possible?
SELECT FROM_UNIXTIME(timestamp)
FROM report_data
WHERE timestamp = '1399376713'
I used this to convert to human readable format.
My database is something like this
timestamp event_type flags
1399357862 701 null
I want to give a particular date in my query and get the result.
It's possible using the FROM_UNIXTIME function.
This assumes that your table contains columns in DATETIME or TIMESTAMP, and you are wanting to supply 32-bit integer values in the query.
For example:
SELECT ...
FROM mytable t
WHERE t.datetime_col >= FROM_UNIXTIME( ? )
AND t.datetime_col < FROM_UNIXTIME( ? )
The integer values supplied as arguments to the FROM_UNIXTIME function will be interpreted as unix-style "seconds since epoch" integer values, and be converted to a DATETIME value using the current timezone setting of the client connection.
This approach will enable MySQL to use a range scan operation using an index with a leading column of datetime_col.
What's not at all clear is what the datatype of your column is, and what values you want to supply in the query. If the columns is datatype DATE, DATETIME or TIMESTAMP (which would be the normative pattern for storing date/time data), then you can specify date literals in standard MySQL format, 'YYYY-MM-DD HH:MM:SS'.
WHERE t.timestamp_col >= '2015-02-11 07:00'
AND t.timestamp_col < '2015-02-11 23:30:00'
If you are storing the "timestamp" as an integer value, then you will need the right side of the predicates to return an integer value, e.g.
WHERE t.integer_col >= UNIX_TIMESTAMP('2015-02-10')
AND t.integer_col < UNIX_TIMESTAMP('2015-02-10' + INTERVAL 24 HOUR)

convert date from numeric value to date valid format

I need to filter all dates which greater than, say 01 january 2011.
select * from table_name where date > '01/01/2011';
the problem is that date field store int values, here is an example:
1339011098
1336717439
1339010538
How to convert the date field on the sql query (from the int format to date format), I need to convert it to a valid date so that I can compare it towards the above date.
Thanx.
You're going the wrong direction. Rather than converting potentially millions of records for the compare, try converting your target date, which you only need to do once. Those look like unix timestamps, so the resulting query should look like this:
SELECT * FROM `Table_name` WHERE date > unix_timestamp('01/01/2011')
Or, if you can control this, try using the ISO date format, which avoids confusion with european date formats for dates like 3/2/13:
SELECT * FROM `Table_name` WHERE date > unix_timestamp('2011-01-01')
You can use UNIX_TIMESTAMP()
select *
from table_name
where date > unix_timestamp('2011-01-01')
Or conversely use FROM_UNIXTIME()
select *
from table_name
where FROM_UNIXTIME(date, "%Y-%m-%d") > '2011-01-01'
First, you should not store date values as integers and if it's under your control your goal should be to fix the database and any queries that insert an integer value for that column instead of date.
The two date functions that you need to use with the current setup are UNIX_TIMESTAMP(), which accepts a date value and returns the epoch timestamp integer and FROM_UNIXTIME() which accepts an epoch timestamp integer and returns a date value.
For your example, you could use either:
SELECT * FROM table_name WHERE FROM_UNIXTIME(date_field) > '01/01/2011';
or
SELECT * FROM table_name WHERE date_field > UNIX_TIMESTAMP('01/01/2011');
But I would advise using FROM_UNIXTIME as a general rule as this would simplify more sophisticated queries such as:
SELECT * FROM table_name WHERE
FROM_UNIXTIME(date_field)
BETWEEN '01/01/2013' AND '04/01/2013';
Essentially, until your date field is actually storing values that are date types, your queries should covert the field values with FROM_UNIXTIME.

How to combine date and time from different MySQL columns to compare to a full DateTime?

Column d is DATE, column t is time, column v is, for example, INT. Let's say I need all the values recorded after 15:00 of 01 Feb 2012 and on. If I write
SELECT * FROM `mytable` WHERE `d` > '2012-02-01' AND `t` > '15:00'
all the records made before 15:00 at any date are going to be excluded from the result set (as well as all made at 2012-02-01) while I want to see them. It seems it would be easy if there were a single DATETIME column, but there are separate columns for date and time instead in the case of mine.
The best I can see now is something like
SELECT * FROM `mytable` WHERE `d` >= '2012-02-02' OR (`d` = '2012-02-01' AND `t` > '15:00')
Any better ideas? Maybe there is a function for this in MySQL? Isn't there something like
SELECT * FROM `mytable` WHERE DateTime(`d`, `t`) > '2012-02-01 15:00'
possible?
You can use the mysql CONCAT() function to add the two columns together into one, and then compare them like this:
SELECT * FROM `mytable` WHERE CONCAT(`d`,' ',`t`) > '2012-02-01 15:00'
The TIMESTAMP(expr1,expr2) function is explicitly for combining date and time values:
With a single argument, this function returns the date or datetime
expression expr as a datetime value. With two arguments, it adds the
time expression expr2 to the date or datetime expression expr1 and
returns the result as a datetime value.
This resulting usage is just what you predicted:
SELECT * FROM `mytable` WHERE TIMESTAMP(`d`, `t`) > '2012-02-01 15:00'
Here's a clean version that doesn't require string operations or conversion to to UTC timestamps across time zones.
DATE_ADD(date, INTERVAL time HOUR_SECOND)
All you have to do is to convert it into unix timestamp and make appropriate selections. For this you have to use mysql functions like *unix_timestamp().* and *date_format*
Suppose you want to select rows where timestamp > 1328725800, the following sql statement would do the task.
select unix_timestamp(d)+3600*date_format(t,'%h)+60*date_format(t,'%i')+date_format(t,'%S') as timestamp from table where timestamp>1328725800
Actually it should be:
SELECT * FROM `mytable` WHERE CONCAT(`d`,' ',`t`) > '2012-02-01 15:00:00'
If you want to take seconds into account, you need to add the two digits to the end ;)