I get the following error when I try to insert the datetime value in a timestamp field in my MySQL table. I am trying to do this by running a Python code.
_mysql_exceptions.OperationalError: (1292, "Incorrect datetime value: '2018-03-26 10:59:27+00:00' for column 'timestamp' at row 1")
Is there a workaround or a solution to this error ?
2018-03-26 10:59:27+00:00
This is a valid iso-8601 datetime value, but it is not a valid MySQL datetime literal. On that point, the developer is incorrect.
The documentation explains what ALLOW_INVALID_DATES does:
Check only that the month is in the range from 1 to 12 and the day is in the range from 1 to 31.
In other words, 2018-03-26 would be a permissible date if allow_invalid_dates is set. This option does not do anything when the date or datetime isn't even in a valid format for MySQL.
The +00:00 is the timezone offset from UTC. In this case, the time expressed is in UTC, so the offset is zero hours, zero minutes.
Your workaround would be to remove the STRICT_TRANS_TABLES from the sql_mode that is a default in the config file created during the MySQL 5.6 installation process... you need to carefully consider the implications of changing this, but it does allow the data to go in.
mysql> select ##sql_mode;
+--------------------------------------------+
| ##sql_mode |
+--------------------------------------------+
| STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
+--------------------------------------------+
1 row in set (0.00 sec)
mysql> insert into datetimetest(dt) values ('2018-03-26 10:59:27+00:00');
ERROR 1292 (22007): Incorrect datetime value: '2018-03-26 10:59:27+00:00' for column 'dt' at row 1
-- remove STRICT_TRANS_TABLES -- note that executing this only removes it for your
-- current session -- it does not make a server-wide config change
mysql> set ##sql_mode='no_engine_substitution';
Query OK, 0 rows affected (0.00 sec)
mysql> select ##sql_mode;
+------------------------+
| ##sql_mode |
+------------------------+
| NO_ENGINE_SUBSTITUTION |
+------------------------+
1 row in set (0.00 sec)
-- now MySQL will accept the invalid value, with a warning
mysql> insert into datetimetest(dt) values ('2018-03-26 10:59:27+00:00');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+-----------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------+
| Warning | 1265 | Data truncated for column 'dt' at row 1 |
+---------+------+-----------------------------------------+
1 row in set (0.00 sec)
-- the value did get inserted, but the time zone information was lost:
mysql> select * from datetimetest;
+----+---------------------+
| id | dt |
+----+---------------------+
| 1 | 2013-08-26 12:00:00 |
+----+---------------------+
1 row in set (0.00 sec)
Related
I need your help. I am trying to transform a text field (containing: 2020-09-11T08:32:50Z) into a date field. I have tried with TIMESTAMP statement and I get the warning: 1292 Truncated incorrect datetime value.
I have also tried with STR_TO_DATE statement and I get another warning: 1411 Incorrect datetime value.
I have entered SET ##SESSION.sql_mode='ALLOW_INVALID_DATES' to avoid some configuration error, but the error remains.
Thanks a lot!
MySQL understands the format up to the 'Z'. If you remove the 'Z' it will work fine.
Demo:
mysql> select date('2020-09-11T08:32:50Z');
+------------------------------+
| date('2020-09-11T08:32:50Z') |
+------------------------------+
| 2020-09-11 |
+------------------------------+
1 row in set, 1 warning (0.01 sec)
mysql> show warnings;
+---------+------+------------------------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect datetime value: '2020-09-11T08:32:50Z' |
+---------+------+------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select date('2020-09-11T08:32:50');
+-----------------------------+
| date('2020-09-11T08:32:50') |
+-----------------------------+
| 2020-09-11 |
+-----------------------------+
1 row in set (0.00 sec)
No warning is returned if the 'Z' is removed.
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;
I have a database with a column named date (timestamp) which is set to default CURRENT_TIMESTAMP. This used to work fine, however after migrating the database to a different server the timestamp only gets applied after an UPDATE query is performed, an INSERT query just sets it to "0000-00-00 00:00:00".
I suspect that whatever is doing the insert is putting an empty string into the field. Look at this result;
MariaDB [horizon]> create table foo (t timestamp default current_timestamp not null);
Query OK, 0 rows affected (0.02 sec)
MariaDB [horizon]> insert into foo values ('');
Query OK, 1 row affected, 1 warning (0.01 sec)
MariaDB [horizon]> select * from foo;
+---------------------+
| t |
+---------------------+
| 0000-00-00 00:00:00 |
+---------------------+
1 row in set (0.00 sec)
I would check the code that is doing the insert - if it's coming from a web form the form itself could be submitting an empty string. You really need to insert null or leave the column out of the INSERT to get the default.
MariaDB [horizon]> insert into foo values (null);
Query OK, 1 row affected (0.01 sec)
MariaDB [horizon]> insert into foo values ();
Query OK, 1 row affected (0.00 sec)
MariaDB [horizon]> select * from foo;
+---------------------+
| t |
+---------------------+
| 0000-00-00 00:00:00 |
| 2017-09-19 21:41:16 |
| 2017-09-19 21:41:20 |
+---------------------+
3 rows in set (0.00 sec)
I am running MySQL 5.7 and wanted to convert some strings to date. I referred the manual here:
http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_str-to-date
And tried out the following(please note the MySQL version)
mysql> SELECT STR_TO_DATE('9','%m');
+-----------------------+
| STR_TO_DATE('9','%m') |
+-----------------------+
| NULL |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+--------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------+
| Warning | 1411 | Incorrect datetime value: '9' for function str_to_date |
+---------+------+--------------------------------------------------------+
1 row in set (0.00 sec)
But from the online manual for MySQL 5.7, I should see the following:
mysql> SELECT STR_TO_DATE('9','%m');
-> '0000-09-00'
Is there something that I'm missing, or could this be a bug?
As it says in the manual,
If the NO_ZERO_DATE or NO_ZERO_IN_DATE SQL mode is enabled, zero dates or part of dates are disallowed. In that case, STR_TO_DATE() returns NULL and generates a warning
That causes the result to be NULL in cases such like this, because your partial “date” contains zero values.
I have a table with some rows and within them there is a definition that goes like this:
`metric_update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
So what i actually want it to do is to automatically insert a timestamp when inserting data into that table. And it does. But what I need is to write a GMT based time into that field (current server time is like GMT+2).
Is there a way to say to MYSQL to do such thing?
If your server time and timezone settings are configured correctly, then internally all times stored in TIMESTAMP columns are converted to GMT (since that's what Unix timestamp mandates). They're converted back to your session timezone when you retrieve this data. If you want it presented in GMT timezone, you need to do conversion while retrieving data not while inserting.
See the console dump below for example. You can run these commands yourself to check.
mysql> use test;
Database changed
mysql> -- let's create a table we'll be working with
mysql> CREATE TABLE tsTable (
-> ID INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
-> ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-> );
Query OK, 0 rows affected (0.08 sec)
mysql> -- let's check current time as well as timezone settings
mysql> SELECT CURTIME(),##global.time_zone, ##session.time_zone;
+-----------+--------------------+---------------------+
| CURTIME() | ##global.time_zone | ##session.time_zone |
+-----------+--------------------+---------------------+
| 16:25:51 | SYSTEM | +02:00 |
+-----------+--------------------+---------------------+
1 row in set (0.05 sec)
mysql> -- inserting empty row to table to trigger auto timestamp
mysql> INSERT INTO tsTable VALUES (null,null);
Query OK, 1 row affected (0.00 sec)
mysql> -- looks like the time in my local timezone is stored in table
mysql> SELECT * FROM tsTable;
+----+---------------------+
| ID | ts |
+----+---------------------+
| 1 | 2011-07-28 16:26:25 |
+----+---------------------+
1 row in set (0.00 sec)
mysql> -- switching to GMT
mysql> SET SESSION time_zone = '+0:00';
Query OK, 0 rows affected (0.00 sec)
mysql> -- check current time and timezone settings again
mysql> SELECT CURTIME(),##global.time_zone, ##session.time_zone;
+-----------+--------------------+---------------------+
| CURTIME() | ##global.time_zone | ##session.time_zone |
+-----------+--------------------+---------------------+
| 14:27:53 | SYSTEM | +00:00 |
+-----------+--------------------+---------------------+
1 row in set (0.00 sec)
mysql> -- note: CURTIME() returns time two hours 'earlier' than before
mysql> -- let's see what's stored in the table again
mysql> SELECT * FROM tsTable;
+----+---------------------+
| ID | ts |
+----+---------------------+
| 1 | 2011-07-28 14:26:25 |
+----+---------------------+
1 row in set (0.00 sec)
mysql> -- TIMESTAMP is two hours 'earlier' than before too! Magick!
INSERT INTO table_name(column1, metric_update_time) VALUES('dummy', CONVERT_TZ(CURRENT_TIMESTAMP,'+02:00','+03:00');
This will convert the inserted timestamp from GMT+2 to GMT+3.