I came across what looks like an odd issue with either Zend_Db or PHP's PDO MySQL driver, that perhaps stems from my lack of knowledge of those two.
Let's assume I have a MySQL Table with a NULLable TIME field. If I run a query like this in MySQL client:
UPDATE mytable SET mytime = NULL WHERE id = 1;
Everything works as expected and mytime field will hold NULL as value after this query.
However, if I run the exact same query in PHP through the Zend_Db_Adapter, the mytime field is set to '0:0:0' after such query:
$db->getConnection()->exec('UPDATE mytable SET mytime = NULL WHERE id = 1');
How do I set that TIME field to NULL?
I'm using PHP5.3 with PDO MySQL driver, Zend Framework 1.11 and MySQL 5.1.
What you have should work, i.e.:
$db->getConnection()->exec('UPDATE mytable SET mytime = NULL WHERE id = 1');
That should work. I tested it.
Caveat
If the data type time is NOT NULL, then trying to set it to NULL will cause the value NULL to be defaulted to 00:00:00, which may be unexpected behaviour e.g.:
CREATE TABLE `test` (
`time` datetime NOT NULL
);
Trying to insert or update the time field above with NULL will cause the value 00:00:00 to be inserted.
This is similar for date, datetime, and a few other data types. e.g. Trying to set a data type datetime which is NOT NULL to NULL will default its value to 0000-00-00 00:00:00.
NOTE: Mysql will not throw an error when you try to set a NULL value to a NUT NULL data type, you can change this behaviour by setting MySQL's SQL_MODE to STRICT_ALL_TABLES: see this stackoverflow question.
The Fix
Change the field to allow NULL and it should be fine:
CREATE TABLE `test` (
`time` datetime DEFAULT NULL
);
Now the time field can be set to NULL.
use new Zend_Db_Expr('NULL') instead of NULL :
$zend_null = new Zend_Db_Expr('NULL');
$db->getConnection()->exec("UPDATE mytable SET mytime = $zend_null WHERE id = 1");
Related
I keep receiving an error message when trying to convert a column, CreatedDate, of string date values in my Estimates table into the mySQL date format using str_to_date(). My column of data contains dates in m/d/yy format (for example: 1/26/16 or 3/3/16).
I ran this query:
UPDATE Estimates
SET CreatedDate = str_to_date( CreatedDate, '%c/%e/%y' )
mySQL is returning this error message:
Error
SQL query:
UPDATE Estimates
SET CreatedDate = str_to_date( CreatedDate, '%c/%e/%y' )
MySQL said: #1411 - Incorrect datetime value: '' for function str_to_date
What is wrong with my query?
Disable NO_ZERO_DATE SQL mode:
set #old_sql_mode = ##sql_mode;
set sql_mode = '';
Run your statement:
UPDATE Estimates
SET CreatedDate = NULLIF(str_to_date(CreatedDate, '%c/%e/%y'), FROM_DAYS(0))
Then enable original SQL modes:
set sql_mode = #old_sql_mode;
Disabling NO_ZERO_DATE mode will make STR_TO_DATE return zero date 0000-00-00 for invalid date strings, the same value is returned by FROM_DAYS(0). So NULLIF will convert zero dates to NULL.
This answer was helpful.
The usual strategy for cleaning up data like this is as follows:
ALTER TABLE Estimates CHANGE COLUMN CreatedDate CreatedDateString VARCHAR(255);
ALTER TABLE Estimates ADD COLUMN CreatedDate DATE
UPDATE Estimates SET CreatedDate=STR_TO_DATE(CreatedDateString, '%c/%e/%y'))
WHERE CreatedDateString IS NOT NULL AND CreatedDateString != ''
Then when you're confident everything got converted correctly:
ALTER TABLE Estimates DROP COLUMN CreatedDateString
The advantage to proper DATE fields is they're in a consistent format and when you add an INDEX on them data retrieval is very fast, even on ranges, like:
SELECT * FROM Estimates WHERE CreatedDate BETWEEN '2016-01-01' AND '2016-06-30'
It's hitting blank values in your column.
SET CreatedDate = str_to_date( '', '%c/%e/%y' )
I think this outputs 0000-00-00 and that works as an invalid date if you are setting a date field to that.
SET CreatedDate = STR_TO_DATE( IFNULL(case when CreatedDate = '' then null else createddate end,'1901-1-1'), '%c/%e/%y' )
That will leave 1901-01-01 values for nulls and blank
Added to tadman:
SET CreatedDate = STR_TO_DATE(case when CreatedDate = '' then null else createddate end, '%c/%e/%y' )
Nulls instead of 1901-01-01 if you prefer.
Example Data:
PostID DateTime DataTimeProper UserID UserName IPAddress
1234567.page#00008912 07/25/2013 14:50:21 NULL 00000001 TestUser 127.0.0.1
2468012.page#04208002 07/28/2013 18:42:13 NULL 03209827 BobTest 127.0.0.2
I'm looking for the most efficient way to update every record in a table (millions) where the DateTimeProper column IS NULL with the value being inserted coming from a str_to_date of the DateTime column.
SELECT STR_TO_DATE(`DateTime`,'%m/%e/%Y %H:%i:%s');
It's simply
UPDATE yourTable SET DateTimeProper = STR_TO_DATE(`DateTime`,'%m/%e/%Y %H:%i:%s')
WHERE DateTimeProper IS NULL;
It takes as long as it takes and it's a one time operation anyway, right?
If you really insist, you can make yourself the trouble to update in chunks, like (assuming you have an auto_increment column named id or something)
UPDATE yourTable SET DateTimeProper = STR_TO_DATE(`DateTime`,'%m/%e/%Y %H:%i:%s')
WHERE DateTimeProper IS NULL
AND id BETWEEN 0 AND 10000;
and then
UPDATE yourTable SET DateTimeProper = STR_TO_DATE(`DateTime`,'%m/%e/%Y %H:%i:%s')
WHERE DateTimeProper IS NULL
AND id BETWEEN 10000 AND 20000;
and so on. Some people do that in the hope, that the chunks fit into memory, but in my opinion it's not worth the trouble. MySQL already does a good job at that.
Try this
UPDATE table SET DataTimeProper =
(SELECT STR_TO_DATE(DateTime,'%m/%e/%Y %H:%i:%s'))
WHERE DataTimeProper IS NULL
Although you should consider changing your DateTime column to be of type DATETIME instead of string, as this will make it more efficient. Especially as you're dealing with tables of multi-million rows.
I have some SQL code below which enables me to change all instances of quantities that are '0' and change them to '1' within the 'quantity' column only. It works ok but...
What I am trying to do, however, is not affect the timestamp column (called 'entry_date') on the affected rows ie. keep the original time the entry was made. When I run this query it replaces the time the entry was originally made with the time the query below was ran.
How do I get around this? I have basic-intermediate PHP knowledge but my SQL knowledge isn't great. Any help would be appreciated.
UPDATE databasename.tablename SET quantity = '1'
WHERE tablename.quantity = '0';
You could try something like this:
UPDATE databasename.tablename SET quantity = '1', entry_date = entry_date
WHERE tablename.quantity = '0';
and see if it doesn't override the behaviour specified by the ON UPDATE CURRENT_TIMESTAMP.
First, DESCRIBE tablename, and note "entry_date" has Extra info "on update CURRENT_TIMESTAMP". That's the behavior you want to avoid.
Next, ALTER TABLE tablename MODIFY COLUMN entry_date TIMESTAMP [NULL | NOT NULL] DEFAULT CURRENT_TIMESTAMP;
(You specify 'NULL' or 'NOT NULL' as appropriate.)
Finally, DESCRIBE tablename again, and note that the Extra info is gone.
When you want timestamp field entry_date to not change automatically on update.. you need following query to execute before any update query on your table
ALTER TABLE `tableName` CHANGE `entry_date` `entry_date` TIMESTAMP NOT NULL
DEFAULT CURRENT_TIMESTAMP
Opposite : After this if you again want timestamp field entry_date to change automatically on update.. you need following query to execute before any update query on your table
ALTER TABLE `tableName` CHANGE `entry_date` `entry_date` TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
I want to create a table with two column, one "created" and one "modified", with a timestamp type. I don't want them to have a default value. But when I create them, it automatically puts CURRENT_TIMESTAMP as default for at least one of them, and also on update.
How can I just have type timestamp with no default or on update value for any of my column?
Edit: I use MySQL
If you are using SQL Server, the timestamp type is used for row versioning, not for storing an actual date or time value. See MSDN.
You could create the columns with a datetime datatype and then set your created and modified values with triggers.
CREATE TRIGGER trg_SetDateCreated ON MyTable
FOR INSERT AS
UPDATE MyTable
SET created = CURRENT_TIMESTAMP
WHERE MyTable.id = (SELECT Id FROM Inserted);
GO
CREATE TRIGGER trg_SetDateModified ON MyTable
FOR UPDATE AS
UPDATE MyTable
SET modified = CURRENT_TIMESTAMP
WHERE MyTable.id = (SELECT Id FROM Inserted);
GO
I have a very large table with two INT columns that are null on Default. This is a problem because since they are INT fields, it would help in many cases if they were originally set to 0.
So my questions are, is there a way I can UPDATE and INCREMENT(+1) these fields while they are like this (null on Default)? BTW.. I didn't have luck so far, it seems increment only works when the default=0
..or is my only option to Change the Default to none from null
UPDATE TableName SET column = IFNULL(column, 0) + 1 WHERE ...
More info on IFNULL. It returns the first argument if it is not NULL, the second otherwise.
Try setting the field as NOT NULL to get away with the problem so that default value of 0 is used instead of null. The other option is to set column as zero whenever it is null.
UPDATE TableName SET FieldName = '0' WHERE FieldName IS NULL
Other alternative would be to issue IFNULL to return 0 in case the column is null and then incrementing the column.
UPDATE TableName SET FieldName = IFNULL(FieldName,0)
The SQL standard would be to use COALESCE(); this has been available in MySQL since version 3.23 (which was released into production in 2001):
UPDATE mytable
SET mycolumn = COALESCE(mycolumn, 0) + 1
WHERE my_other_columns = ...
I can't see any reason to choose IFNULL() over COALESCE() here.
Hope this helps.