MSQL parse dates as 21-JUN-14 - mysql

I have some dates exported as varchars from an Oracle database, and the dates are in this format;
20-JAN-13
14-OCT-14 etc etc
How can I parse them? I've been trying things such as STR_TO_DATE(next_event_date, '%d-%mmm-%YY') but no luck, any ideas?
Kind Regards,
Harry

Right from the docs: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
STR_TO_DATE(next_event_date, '%d-%b-%y')
You should also look for the format modifiers here: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format

Try this
SELECT STR_TO_DATE(next_event_date,'%d-%M-%y');
Using your example.
mysql> SELECT STR_TO_DATE('14-OCT-14','%d-%M-%y');
+-------------------------------------+
| STR_TO_DATE('14-OCT-14','%d-%M-%y') |
+-------------------------------------+
| 2014-10-14 |
+-------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT STR_TO_DATE('20-JAN-13','%d-%M-%y');
+-------------------------------------+
| STR_TO_DATE('20-JAN-13','%d-%M-%y') |
+-------------------------------------+
| 2013-01-20 |
+-------------------------------------+
1 row in set (0.00 sec)
mysql>

Related

Converting substring to DATE with str_to_date

I've got probably what is a very simple issue. However, I've researched extensively and haven't found a solution yet. Basically, I want to convert a modified string variable into the DATE format (specifically %Y).
I have a column variable called dob, which includes dates in the VARCHAR format. The values of these strings vary and can look like any of the following: 01 JAN 1900, ABT 1960, or Unknown. Nonetheless, the year is always the last four digits, so I'm grabbing the year by creating a substring. But I want to convert that substring into a YEAR format. My thought is that I need to use str_to_date to accomplish this.
This is my MySQL query:
SELECT dob, STR_TO_DATE(SUBSTRING(dob, -4), "%Y") as YEAR
FROM person_table;
Upon running it, I only get NULL values. Is there something I'm missing?
Here are my MySQL specs:
innodb_version: 5.7.20
protocol_version: 10
Thanks for your help!
Edit: Providing SQL Mode Information:
+---------------+-----------------------------------------------------------+
| Variable_name | Value |
+ --------------+-----------------------------------------------------------+
| sql_mode | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+------------------------------------------------------------
1 row in set (0.00 sec)
Upon running the query SELECT STR_TO_DATE('2009','%Y'); I get NULL and the following warning:
I get the following warning:
+---------+------+-----------------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------------+
| Warning | 1411 | Incorrect datetime value: '2009' for function str_to_date |
+---------+------+-----------------------------------------------------------+
1 row in set (0.00 sec)
str_to_date returns a date type, and only a year is an incomplete date. str_to_date will fill in the incomplete parts with zeroes unless you have no_zero_dates mode enabled. This is part of Strict SQL Mode which is the default in MySQL 8.0; it avoids the worst of MySQL's quirks.
Strict mode controls how MySQL handles invalid or missing values in data-change statements such as INSERT or UPDATE. A value can be invalid for several reasons. For example, it might have the wrong data type for the column, or it might be out of range
Without Strict SQL Mode, MySQL will turn "2009" into the invalid date 2009-00-00.
mysql> set sql_mode = '';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT STR_TO_DATE('2009','%Y');
+--------------------------+
| STR_TO_DATE('2009','%Y') |
+--------------------------+
| 2009-00-00 |
+--------------------------+
1 row in set (0.00 sec)
With Strict SQL Mode it will not.
mysql> show variables like 'sql_mode';
+---------------+-----------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+-----------------------------------------------------------------------------------------------------------------------+
| sql_mode | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+---------------+-----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT STR_TO_DATE('2009','%Y');
+--------------------------+
| STR_TO_DATE('2009','%Y') |
+--------------------------+
| NULL |
+--------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+-----------------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------------+
| Warning | 1411 | Incorrect datetime value: '2009' for function str_to_date |
+---------+------+-----------------------------------------------------------+
1 row in set (0.00 sec)
To solve your problem, instead of trying to do a one-size-fits-all conversion, I would recommend trying several formats from most to least specific using coalesce. You will have to add the missing date parts as needed.
select coalesce(
str_to_date(dob, '%d %b %Y'),
str_to_date(concat(dob, '-01-01'), 'ABT %Y-%m-%d')
)
from person_table;
As this is very ugly to do, I also would recommend adding a proper date column and doing an update to convert from the messy string dates to proper dates. Then query the new column going forward.
alter table person_table add column dob_date date;
update person_table
set dob_date = coalesce(
str_to_date(dob, '%d %b %Y'),
str_to_date(concat(dob, '-01-01'), 'ABT %Y-%m-%d')
)
where dob_date is null;
You can then check for people with a null dob_date, examine their dob field, and adapt your conversion. Iterate as needed.
UPDATE
To add, yes, I need the year 2020 as opposed to the string. The reason being is because I need to compare the year values.
As strings they will not compare as you need. Strings compare character by character. '200' is greater than the string '1999'.
mysql> select '1999' < '2000';
+-----------------+
| '1999' < '2000' |
+-----------------+
| 1 |
+-----------------+
1 row in set (0.00 sec)
mysql> select '1999' < '200';
+----------------+
| '1999' < '200' |
+----------------+
| 1 |
+----------------+
1 row in set (0.00 sec)
You need to cast them to signed integers.
mysql> select cast("1999" as signed) < cast('2000' as signed);
+-------------------------------------------------+
| cast("1999" as signed) < cast('2000' as signed) |
+-------------------------------------------------+
| 1 |
+-------------------------------------------------+
1 row in set (0.00 sec)
mysql> select cast("1999" as signed) < cast('200' as signed);
+------------------------------------------------+
| cast("1999" as signed) < cast('200' as signed) |
+------------------------------------------------+
| 0 |
+------------------------------------------------+
1 row in set (0.01 sec)
So your query would be...
select dob, cast(substring(dob, -4) as signed) as year
from person_table;

substract timediff from time value

This is my table:
+----------+---------------------+
| estimate | timestamp |
+----------+---------------------+
| 05:00:00 | 2015-12-02 13:35:14 |
+----------+---------------------+
1 row in set (0.00 sec)
I am trying to implement a scheduled job to create extra automatic rows every hour to substract the time that has past from the estimated time.
I am able to start the scheduled job and use timediff to calculate the time that has passed since, but i am unable to substract the timediff from the estimated time.
I am guessing that mysql doesn't care much that i want the estimated time column to be stated as a period of time. instead, it just shows me a time without the date.
select timediff(now(),timestamp) from t1;
this gives me the time difference that i need:
+---------------------------+
| timediff(now(),timestamp) |
+---------------------------+
| 00:27:03 |
+---------------------------+
1 row in set (0.00 sec)
but when i do this:
select estimate-timediff(now(),timestamp) as timeleft from t1;
the result is:
+----------+
| timeleft |
+----------+
| 46568 |
+----------+
1 row in set (0.01 sec)
what i would like to get:
+----------+
| timeleft |
+----------+
| 04:32:57 |
+----------+
1 row in set (0.01 sec)
The times may be a little off in my example obviously because of the timediff() but hopefully you understand my issue. There must be an easy solution that i'm missing but i've spent half a day googleing to get to this point but timediff just won't cut me some slack.
Please and thank you!
PS. I haven't found the solution yet but i think i found what might cause the problem. Obvioysly the substraction is done by using absolute values 'estimate' column doesn't use seconds as it's absolute value and the result is completely wrong.
mysql> select abs(estimate) from t1;
+----------+
| abs(estimate) |
+----------+
| 50000 |
+----------+
1 row in set (0.00 sec)
and
mysql> select abs(timediff(now(),timestamp)) from t1;
+--------------------------------+
| abs(timediff(now(),timestamp)) |
+--------------------------------+
| 2318 |
+--------------------------------+
1 row in set (0.00 sec)
So is there an easy way to force mysql to use seconds on a time column? or is something wrong with my table and the estimate format is wrong?
use timediff like that :-
timediff(estimate,timediff(now(),timestamp))
your query :-
select timediff(estimate,timediff(now(),timestamp))
as timeleft from t1;

Is it possible to configure MySQL to return TIMESTAMP value as a UNIXTIMESTAMP?

Is it possible to configure MySQL to return TIMESTAMP value as a UNIXTIMESTAMP by default, rather than casting every column in the SELECT statement?
MySQL has a function to convert a date to a unix timestamp.
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_unix-timestamp
mysql> SELECT UNIX_TIMESTAMP();
-> 1196440210
mysql> SELECT UNIX_TIMESTAMP('2007-11-30 10:30:19');
-> 1196440219
You cannot do that in MySQL configuration.
You can do that on application level - e.g. in PHP, you can use the mysqli_result::fetch_fields() method to detect timestamp type and convert it, other connectors will have similar methods.
Or you can do it - as suggested - using UNIX_TIMESTAMP() function on timestamp columns.
It sounds as though you want a different view of the same data:
mysql> select * from t;
+------+---------------------+
| data | ts |
+------+---------------------+
| foo | 2013-03-19 16:54:45 |
+------+---------------------+
1 row in set (0.00 sec)
mysql> select data, unix_timestamp(ts) from t;
+------+--------------------+
| data | unix_timestamp(ts) |
+------+--------------------+
| foo | 1363712085 |
+------+--------------------+
1 row in set (0.00 sec)
mysql> create view tv (data, time_t) as select data, unix_timestamp(ts) from t;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tv;
+------+------------+
| data | time_t |
+------+------------+
| foo | 1363712085 |
+------+------------+
1 row in set (0.00 sec)

ANSI 92 Date Difference not working in MySQL

I'm, trying to calculate the number of days between two dates using ANSI SQL standard. But I'm missing something as this statement returns NULL in MySQL.
SELECT EXTRACT(DAY FROM DATE('2009-01-25') - DATE('2009-01-01')) AS day_diff;
I'm aware of the MySQL DATEDIFF function, but I'm curious why this code isn't working.
What am I missing?
Is this what you meant to do?
mysql> SELECT EXTRACT(DAY FROM DATE('2009-01-25')) -
EXTRACT(DAY FROM DATE('2009-01-01')) AS day_diff;
+----------+
| day_diff |
+----------+
| 24 |
+----------+
1 row in set (0.00 sec)
UPDATE:
If you want this to work for dates in different months (or even different years), then you can use the MySQL DATEDIFF() function.
Examples:
mysql> select datediff('2009-04-25','2009-01-01');
+-------------------------------------+
| datediff('2009-04-25','2009-01-01') |
+-------------------------------------+
| 114 |
+-------------------------------------+
1 row in set (0.00 sec)
mysql> select datediff('2010-04-25','2009-01-01');
+-------------------------------------+
| datediff('2010-04-25','2009-01-01') |
+-------------------------------------+
| 479 |
+-------------------------------------+
1 row in set (0.00 sec)

MySQL & Regex (checking for proper name capitalization)

I'm trying to check if a name has invalid characters, so far I've managed to get everything I need apart from checking for capitalization, I've tried using
SELECT BINARY('jiLl') REGEXP('[[:upper:]]+');
but unfortunately that also flags properly formatted names, as in (Jack), is it possible to have the regex ignore the first character of the name, and if so how?
Thank you in advance,
--a
Take one step back and rethink ;)
Give me all instances that don't start with a capital letter and the rest are lower-case:
mysql> SELECT BINARY('JacK') NOT REGEXP('^[[:upper:]][[:lower:]]+$') AS is_invalid;
+------------+
| is_invalid |
+------------+
| 1 |
+------------+
1 row in set (0.00 sec)
mysql> SELECT BINARY('jiLl') NOT REGEXP('^[[:upper:]][[:lower:]]+$') AS is_invalid;
+------------+
| is_invalid |
+------------+
| 1 |
+------------+
1 row in set (0.00 sec)
mysql> SELECT BINARY('Jack') NOT REGEXP('^[[:upper:]][[:lower:]]+$') AS is_invalid;
+------------+
| is_invalid |
+------------+
| 0 |
+------------+
1 row in set (0.00 sec)