Is there any way to convert the warning that MySQL is issuing about an invalid datetime into a hard error? I've tried using SET sql_mode='TRADITIONAL'; which apparently is supposed to turn (some) things that are warnings into errors, but it does not have any effect here. This is MySQL 5.1.56. Something that works on a session-level would be ideal, but I'll take what I can get.
mysql> describe test_table2;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| value | int(11) | YES | | NULL | |
| name | varchar(16) | YES | | NULL | |
| sometime | datetime | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> select * from test_table2;
+-------+-------+---------------------+
| value | name | sometime |
+-------+-------+---------------------+
| 1 | one | 2002-09-01 10:00:00 |
| 2 | two | 2002-09-02 11:00:00 |
| 3 | three | 2002-09-03 12:00:00 |
| 4 | four | 2002-01-04 13:00:00 |
| 5 | five | 2002-01-05 14:00:00 |
+-------+-------+---------------------+
5 rows in set (0.00 sec)
mysql> select * from test_table2 where sometime = 'foo';
Empty set, 2 warnings (0.00 sec)
Warning (Code 1292): Incorrect datetime value: 'foo' for column 'sometime' at row 1
Warning (Code 1292): Incorrect datetime value: 'foo' for column 'sometime' at row 1
With SET sql_mode='TRADITIONAL', doing an INSERT with an invalid date causes an error, but doing a SELECT with an invalid date still causes a warning. You can trigger the error by passing the (possibly invalid) date value to this query first:
CREATE TEMPORARY TABLE IF NOT EXISTS date_guard (date DATE) SELECT 'foo' AS date;
where 'foo' is the date value you want to validate.
Who is supposed to see the error?
If this is a fixed string 'foo' just try converting 'foo' to a date and see if you can a valid result (i.e. not 00-00-000). Do a pre-query to check the validity of the date, and then continue after.
I have not been able to make MySQL give an error in this case (or even convert the invalid date to a NULL - it insists on making it 00-00-0000).
Related
I am running a mysql query using golang:
query: UPDATE RESTORE_TIMESTAMP SET last_restored_at=? where id=?, updatedTime, 1
Here updatedTime is in strfmt.DateTime format in go.
This query runs fine for some time but after that it starts failing with below error.
Sometimes after mysql retries it passes but most of the times it is failing.
I'm not getting any clue why is this happening.
Error 1292: Incorrect datetime value: '2020-10-19T16:25:08.958Z' for column db.RESTORE_TIMESTAMP.last_restored_at at row 1"
table details:
MariaDB [db]> show columns from RESTORE_TIMESTAMP;
+------------------+-----------+------+-----+---------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+-----------+------+-----+---------------------+-------+
| id | enum('1') | NO | PRI | NULL | |
| last_restored_at | timestamp | NO | | current_timestamp() | |
+------------------+-----------+------+-----+---------------------+-------+
2 rows in set (0.001 sec)
I have only one row in my table as above and I need to update that every time.
Please point me somewhere how can I resolve this query failure.
You should to apply STR_TO_DATE conversion for convert your date into DB format
UPDATE RESTORE_TIMESTAMP
SET last_restored_at=STR_TO_DATE(?, '%Y-%m-%dT%H:%i:%s.%fZ')
WHERE id=?;
Test it on SQLize.online
I need convert in my table of DB MySQL the column values from VARCHAR(255) to DECIMAL (10,5).
I have tried this SQL query in which first replace ',' with '.' and then set new the column values to DECIMAL (10,5):
[SQL]UPDATE `doTable`
SET doAV = REPLACE (doAV, ',', '.')
WHERE
YEAR (`doDate`) IN (YEAR(CURDATE()));
Affected rows: 83169
Time: 1.846s
[SQL]
ALTER TABLE `doTable` MODIFY COLUMN doAV DECIMAL (10, 5);
[Err] 1292 - Truncated incorrect DECIMAL value: '2226,000'
But I have error:
[Err] 1292 - Truncated incorrect DECIMAL value: '2226,000'
How to do resolve this?
Can you help me?
Thank you in advance for any help, really appreciated.
#Edit 01
+----------+
| doAV |
+----------+
| 2226.000 |
| 2226.00 |
| 2225.750 |
| 2225.600 |
| 2225.533 |
| 2225.250 |
| 2225.000 |
| 2225.00 |
| 2224.800 |
| 2224.667 |
+----------+
#Edit 02
+-----------+
| doAV |
+-----------+
| 2226.000 |
| 792.000 |
| 338.400 |
| 13635.000 |
| 1438.125 |
| 220.800 |
| 172.000 |
| 253.000 |
| 4258.500 |
| 352.800 |
+-----------+
I think you updated only rows in YEAR (doDate) IN (YEAR(CURDATE())). Try to update all the rows first of all. Delete WHERE condition from your UPDATE and run it again.
Try to check only the whole part
SELECT *
FROM doTable
WHERE LENGTH(LEFT(doAV,IFNULL(NULLIF(LOCATE('.',doAV)-1,-1),LENGTH(doAV))))>5
DECIMAL(10, 5) => your whole part can containt only 5 digitals (10-5=5).
As I am not the world's greatest SQLer, I am working up to something big, step by step.
I have a table:
mysql> describe taps;
+---------------+-----------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-----------+------+-----+-------------------+-------+
| tag_id | int(11) | YES | | NULL | |
| time_stamp | timestamp | NO | | CURRENT_TIMESTAMP | |
| event_id | int(11) | YES | | NULL | |
| event_station | int(11) | YES | | NULL | |
| device_id | text | YES | | NULL | |
| device_type | text | YES | | NULL | |
+---------------+-----------+------+-----+-------------------+-------+
6 rows in set (0.00 sec)
And would like to select all entries for a given date (today, 12th Feb, '17).
I am trying
mysql> select * from taps WHERE (event_id=4)
AND ((time_stamp >= 1486857600000) AND (time_stamp <= 1486944000000));
Empty set, 2 warnings (0.00 sec)
IMPORTANT: I have simplified things, because I want to compare with variables, which have values which I have obtained from another table, which are also of type timestamp.
Hmmm, warnings ....
mysql> SHOW WARNINGS;
+---------+------+----------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------------------------------------------+
| Warning | 1292 | Incorrect datetime value: '1486857600000' for column 'time_stamp' at row 1 |
| Warning | 1292 | Incorrect datetime value: '1486944000000' for column 'time_stamp' at row 1 |
+---------+------+----------------------------------------------------------------------------+
2 rows in set (0.00 sec)
So, I tried casting
select * from taps WHERE (event_id=4)
AND ((time_stamp >= CAST(1486857600000 AS DATETIME))
AND (time_stamp <= CAST(1486944000000 AS DATETIME)));
Empty set (0.00 sec)
Which I don't understand, as I am the table does have some entries today.
mysql> select * from taps order by time_stamp limit 3;
+--------+---------------------+----------+---------------+-----------+-------------+
| tag_id | time_stamp | event_id | event_station | device_id | device_type |
+--------+---------------------+----------+---------------+-----------+-------------+
| 44 | 2017-02-12 15:10:25 | NULL | 16 | NULL | NULL |
| 37 | 2017-02-12 15:10:27 | NULL | 14 | NULL | NULL |
| 50 | 2017-02-12 15:10:28 | NULL | 15 | NULL | NULL |
+--------+---------------------+----------+---------------+-----------+-------------+
3 rows in set (0.00 sec)
What am I doing wrongly? And what should my query be?
MySQL has very confusing terminology for date/time stuff (see here). A timestamp is essentially a datetime with a timezone, because the value is stored as UTC, but reported in the local timezone.
This timestamp is not to be confused with a Unix Timestamp, which is just the number of seconds since 1970-01-01 (or in some cases milliseconds).
In your case, try this:
select t.*
from taps t
where event_id = 4 and
time_stamp >= '2017-02-11 07:00:00' and
time_stamp < '2017-02-12 07:00:00';
You could use from_unixtimestamp(). However, people generally find date formats much easier to read.
Note: I changed the last condition to a strict inequality. This gives you 24 hours with no duplication of time, in case something happens at exactly 2017-02-12 07:00:00.
In SQL, literal TIMESTAMP values are normally supplied as strings, in the format 'YYYY-MM-DD HH:MM:SS'. MySQL does allow some latitude in the actual format. More recent versions of MySQL allow for fractional seconds. See the MySQL Reference Manual for a more complete description.
https://dev.mysql.com/doc/refman/5.6/en/datetime.html
As an example, MySQL would recognize any of these:
'2017-02-12 09:30:45'
'17-02-12 09:30:45'
170212093045
If we have a requirement to supply/specify literal values that represent integer milliseconds since '1970-01-01 00:00:00', we can use a SQL expression to convert those to values that can be compared to TIMESTAMP. As a demonstration:
SELECT '1970-01-01' + INTERVAL 1486857600000 / 1000 SECOND AS ts
If we need to supply integer millisecond values as a literal in a condition in a WHERE clause, then we can use expressions like the one above.
The query in the question could do something like this to compare the value in a TIMESTAMP column
AND time_stamp >= '1970-01-01' + INTERVAL 1486857600000 / 1000 SECOND
AND time_stamp < '1970-01-01' + INTERVAL 1486944000000 / 1000 SECOND
I am currently learning the basics of creating a database and doing some line of data analysis. i have been struggling to understand how to 'start coding'
so i finally decided to come up with a simple diary project to kick start my coding life.
Here is what i have so far, in terms of python so far nothing except i managed to link python and mysql.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| diary |
| mysql |
| performance_schema |
| sakila |
| sys |
| world |
+--------------------+
7 rows in set (0.00 sec)
mysql> desc diary;
+---------------+--------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+-------------------+-------+
| TASK_COMMENTS | varchar(255) | YES | | NULL | |
| TASK | varchar(55) | NO | | NULL | |
| TS | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------------+--------------+------+-----+-------------------+-------+
3 rows in set (0.00 sec)
mysql> select * from diary;
+---------------+---------------+---------------------+
| TASK_COMMENTS | TASK | TS |
+---------------+---------------+---------------------+
| NULL | Food Shopping | 2016-12-25 18:53:32 |
+---------------+---------------+---------------------+
1 row in set (0.00 sec)
here is the question finally:): Is it correct if i make the time stamp a primary key or is it more 'database error-free' to create an actual id instead of using automated timestamp as the pk?
also i am trying to make TASK_COMMENTS field not null aswell but i get this:
mysql> ALTER TABLE Diary MODIFY COLUMN TASK_COMMENTS VARCHAR(255) NOT NULL;
ERROR 1138 (22004): Invalid use of NULL value
Thank you for helping.
You can't alter the default value of a column to NOT NULL if a NULL value already exists. Either delete the row, or set it to something, then you can alter the column.
Using a timestamp is not a good idea for a primary key because it is very possible to get duplicate values. It's also easy not to, but it's just not a good idea. Use an id column, set the PK, and typically one would give it AUTO INCREMENT to ensure no duplicates.
For a preferences module I have "system defaults", and "user preferences".
If there is no personal/user preference stored, then use the system default values instead.
Here is my system preferences table:
mysql> desc rbl;
+-------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+-------+
| id | varchar(3) | NO | PRI | | |
| rbl_url | varchar(100) | NO | | | |
| description | varchar(100) | NO | | | |
| is_default | tinyint(1) unsigned | YES | | 1 | |
+-------------+---------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
Example data from system prefs:
mysql> select * from rbl;
+----+----------------------+------------------------------+------------+
| id | rbl_url | description | is_default |
+----+----------------------+------------------------------+------------+
| 1 | sbl-xbl.spamhaus.org | Spamhaus SBL-XBL | 1 |
| 2 | pbl.spamhaus.org | Spamhaus PBL | 1 |
| 3 | bl.spamcop.net | Spamcop Blacklist | 1 |
| 4 | rbl.example.com | Example RBL - not functional | 0 |
+----+----------------------+------------------------------+------------+
... and Query for system defaults:
mysql> SELECT rbl_url FROM rbl WHERE is_default='1';
+----------------------+
| rbl_url |
+----------------------+
| sbl-xbl.spamhaus.org |
| pbl.spamhaus.org |
| bl.spamcop.net |
+----------------------+
3 rows in set (0.01 sec)
So far so good.
OK. Now I need a user preferences table, and I came up with this:
mysql> desc rbl_pref;
+-----------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-----------------------+------+-----+---------+----------------+
| id | mediumint(8) unsigned | NO | PRI | NULL | auto_increment |
| domain_id | mediumint(8) unsigned | NO | | NULL | |
| rbl_id | tinyint(1) unsigned | NO | | NULL | |
+-----------+-----------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
(FYI - A "user" is represented by "domain_id". )
Let's view the preferences of a specific user who has personalized preferences saved:
mysql> select * from rbl_pref where domain_id='2277';
+----+-----------+--------+
| id | domain_id | rbl_id |
+----+-----------+--------+
| 4 | 2277 | 1 |
| 5 | 2277 | 2 |
| 6 | 2277 | 4 |
+----+-----------+--------+
3 rows in set (0.00 sec)
... again, but in a simpler format:
mysql> SELECT rbl.rbl_url FROM rbl_pref,rbl
WHERE rbl_pref.rbl_id=rbl.id AND domain_id='2277';
+----------------------+
| rbl_url |
+----------------------+
| sbl-xbl.spamhaus.org |
| pbl.spamhaus.org |
| rbl.example.com |
+----------------------+
3 rows in set (0.00 sec)
.. so far so good. If a user has stored a preference, a result is found.
The problem example now is, user 1999 has no custom preferences.
In place of the "Empty set" result, I want the system defaults.
mysql> SELECT rbl.rbl_url FROM rbl_pref,rbl
WHERE rbl_pref.rbl_id=rbl.id AND domain_id='1999';
Empty set (0.00 sec)
I was excited to find a very similar question:
mysql if row doesn't exist, grab default value
However after a couple of days trial and error and documentation review, I could not translate that answer over to here.
Like the above question, this must be done as a single MySQL query. I am not actually making this query from PHP, but from Exim macros (and it is a very picky language... best to feed it "one liners" as variable assignments, as I try to do here.. )
UPDATE: Tried one type of a UNION query suggested by #Biff McGriff, below. The table did not display in my comment reply, so here it is again:
mysql> SELECT rbl.rbl_url FROM rbl_pref,rbl
WHERE rbl_pref.rbl_id=rbl.id AND domain_id='2277'
UNION SELECT rbl_url FROM rbl WHERE is_default='1';
+----------------------+
| rbl_url |
+----------------------+
| sbl-xbl.spamhaus.org |
| pbl.spamhaus.org |
| rbl.example.com |
| bl.spamcop.net |
+----------------------+
4 rows in set (0.00 sec)
As you can see above, user 2277 did not opt in to rbl_id 3 (bl.spamcop.net), but that's showing up anyways.
What my UNION query seems to be doing is combining the result set. So user_pref acts as "in addition to" global defaults, and I was assuming/expecting I would get a result set matching either half of the query.
So my question now is, is it better (or possible, how) to solve this as "either result set" (either subquery on either side of the UNION)? OR do I really need a new field on rbl_pref, called for example "enabled". The latter seems to be more correct - that I need something in rbl_pref to explicitly designate opt-in or opt-out (other than the implicit "that pref is not here - no rbl_id=3 - in the over ridden user result SET")
UPDATE: All set, thanks #Imre L, and everyone else. I learned something through this example.
You should be able to use a left join and then coalesce the user's field with the default field.
NOTE: you have to enter the domain_id in two places.
SELECT rbl.rbl_url FROM rbl
JOIN rbl_pref ON rbl_pref.rbl_id=rbl.id AND domain_id=2277
UNION
SELECT rbl.rbl_url FROM rbl
WHERE rbl.is_default
AND NOT EXISTS (SELECT 1 FROM rbl_pref WHERE domain_id=2277 LIMIT 1)
;
Now one or the other side of UNION will be optimized away with impossible where
You also should not use varchar(3) for rbl.id but some sort of integer
and preferable same type as rbl_pref.rbl_id for which tinyint is too tiny
and when you compare integers fields in sql code domain_id='2277' you should not use ' or " around constants integers.
You can get away whith it mostly but sometimes it may confuse mysql optimizer.
Also for optimal performance and consistency i suggest you the add the index:
ALTER TABLE rbl_pref
ADD UNIQUE INDEX ux_domain_rbl (domain_id, rbl_id);