MySQL Error 1048 + ON DUPLICATE KEY UPDATE + COALESCE - mysql

I'm getting into something very intriguing with MySQL. I have an automated process to insert / update data into a table.
The table has 4 columns (the first 2 make the primary key) and the third is a non nullable varchar. The last column is a bigint
My query looks like this:
INSERT INTO mytable (col1, col2, col3, col4) VALUES('a', 'b', null, 100) ON DUPLICATE KEY UPDATE col3=COALESCE(VALUES(col3), col3), col4=COALESCE(VALUES(col4), col4)
So in theory, the row with the primary key ('a','b') won't have its col3 value changed but col4 should get the value 100.
But since the col3 is not nullable I get the error: "Error Code: 1048. Column 'col3' cannot be null".
Did I get something wrong about the ON DUPLICATE KEY ? How can I achieve this update ?
Thank you in advance for your help.
FYI:
MySQL : v5.7
Engine: InnoDB

Related

Referring to the current field value in the INSERT part of INSERT, ON DUPLICATE KEY UPDATE

When doing an INSERT statement with ON DUPLICATE KEY UPDATE is there a way to refer to the current value of a row and field, when it exists, in the VALUES part of the insert statement? I don't want to refer to it in the ON DUPLICATE KEY UPDATE section.
In my use case, all rows will always exist.
Something like this
INSERT INTO myTable (Col1, Col2) VALUES
('value', myTable.Col2),
('value2', myTable.Col2)
ON DUPLICATE KEY UPDATE
…
I tried this and it nulled all the columns in testing, probably because the reference failed and it returned null instead.
It may be germane to remark that I am trying to do this as part of adding an IF function to an INSERT, ON DUPLICATE KEY UPDATE query with prepared placeholders. So the final version will be like this:
INSERT INTO myTable (Col1, Col2) VALUES
('value', IF(?='test', myTable.Col2, ?),
('value2', myTable.Col2)
ON DUPLICATE KEY UPDATE
…
You can't refer to the current value of the row in the VALUES clause of an INSERT. You'll have to refer to the current value of the row in the ON DUPLICATE UPDATE clause.
For example, you could set the value to NULL in the values clause if your input
INSERT INTO myTable (Col1, Col2) VALUES
('value', NULLIF(?, 'test')), -- default to current value if you insert 'test'
('value2', NULL) -- default to current value always
ON DUPLICATE KEY UPDATE
Col2 = COALESCE(Col2, VALUES(Col2));

Check Constraint based on other column value

I have a table named Table1 with three columns col1, col2, col3.
col1 can have one of the three values(1 or 2 or 3).
I need to add a check constraint such that it checks, if col1 has value 1 then the values of col2 and col3 should be same else if col1 has values 2 or 3, then col2 and col3 values may or may not be same.
Can anyone tell me how to add the constraint for this ?
Thanks in advance.
You can add a check constraint like this:
ALTER TABLE Table1 ADD CONSTRAINT chk_table1_cols
CHECK ( (col1 = 1 AND col2 = col3) OR (col1 IN (2, 3)) );
Note that "is the same" presumes that the values are not NULL. That logic can be added, if you want to consider NULL values as equal.
You can express these condition with a series of logical operators:
(col IN (1, 2, 3)) AND (col2 = col3 OR col1 IN (2, 3)
I didn't verify (I don't have MySql) but in Oracle the following works:
ALTER TABLE Table1 ADD
(
CONSTRAINT CHK_1 CHECK ((col1 BETWEEN 1 AND 3) AND (col1 <> 1 OR col2=col3))
)

MySQL - Insert data in one colum, preserving others, with ON DUPLICATE KEY UPDATE

I have a table with lets say 4 fields.
table:
id(autoincremental), col1, col2, col3
There are several rows with data for id, col1 and col2.
Col3 is empty.
I would like to fill col3 with values, in the existing rows with one query like this:
INSERT INTO table(id, col3)
VALUES
(1, 'value1'),
(2, 'value2'),
(3, 'value3'),
...
ON DUPLICATE KEY UPDATE
id = VALUES(id),
col3 = VALUES(col3);
But I get an error because col1 and col2 don't have a default value.
I just want to update col3, and preserve other column values.
How can I do?
You can use a simple update statement :
Update yourtable t
Set t.col3 = case when t.id = 1 then ‘value1’
case when t.id = 2 then ‘value2’
.....
else t.col3 end;
And you can also filter the desired IDs for better performance
I believe that #Lukasz Szozda comment is the best approach for this issue. So I'll choose it as a solution. Thanks.
Mark col1, col2 as nullable.
You can update like this :
ON DUPLICATE KEY UPDATE
col3 = VALUES(col3);
This will keep the current values for the fields that are not in the update statement.
I read the question again and it seems like your insert would need col1 and col2 as well. You said that they don't have a default value, so I would either
add a default value for each
mark them as nullable
make these parameters mandatory in your application.
So you can't change your table structure my final query would be the following :
INSERT INTO table(id, col1, col2, col3) VALUES
(1, '', '', 'value1'),
(2, '', '', 'value2'),
(3, '', '', 'value3')
-- ...
ON DUPLICATE KEY UPDATE
col1 = col1,
col2 = col2,
col3 = VALUES(col3);
When a field does not have a default value and is not nullable, the insert query must include a value for that field. So your problem is not in the update part of your query, it is in the insert part.

MySQL - INSERT without duplicating rows (without informing the PK)

I have to insert a few values into a mysql table, but only if there are no other (almost) equal rows, for example:
TABLE T
KEY | COL1 | COL2
1 | abc | 123
2 | def | 456
The KEY column uses auto increment, and I don't inform it on the statement, like this:
INSERT INTO T (COL1, COL2) VALUES (abc, 123)
The statement above have the same values as the first row. How can I inform mysql that I don't want to insert if the row is a duplicate like that?
I googled for some solutions and found INSERT IGNORE, ..ON DUPLICATE KEY UPDATE and REPLACE in which I would have to inform the PK, but I don't know it (without using a extra query).
you can do like...
> INSERT INTO memos(id,text)
> SELECT 5, 'text to insert'
> WHERE NOT EXISTS(SELECT 1 FROM memos WHERE id = 5 AND text = 'text to insert');
ON DUPLICATE KEY and INSERT IGNORE will work with any unique index, not just the primary key. So you can add a unique index for these columns:
ALTER TABLE T
ADD UNIQUE INDEX (col1, col2);
Making it a multi-column index means that the combination has to be unique, even though each column can be duplicated individually.
if not exists(select * from t where col1 = "abc" and col2 ="123")then
insert into t (col1,col2) values("abc",123 );
end if;

Detect if MySQL has duplicates when inserting

I have a table with the columns value1, value2 and value3.
Every few months, all rows will need to change their 'value1' to a different value. So far I have the following code and I cannot figure out for the life of me why it is not working. Instead of only modifying column one, it generates an entire new row of information.
Thanks in advance.
INSERT INTO table (value1, value2, value3)
VALUES ('$valueForValue1', '$valueForValue2','$valueForValue3')
ON DUPLICATE KEY UPDATE
`value1`='$valueForValue1',
`value2`='$valueForValue2',
`value3`='$valueForValue3',
In order to be able to change a value of value1 with ON DUPLICATE KEY clause you have to have either a UNIQUE constraint or a PRIMARY KEY on (value2, value3).
ALTER TABLE table1 ADD UNIQUE (value2, value3);
Now to simplify your insert statement you can also use VALUES() in ON DUPLICATE KEY like this
INSERT INTO Table1 (`value1`, `value2`, `value3`)
VALUES ('$valueForValue1', '$valueForValue2', '$valueForValue3')
ON DUPLICATE KEY UPDATE value1 = VALUES(value1);
Here is SQLFIddle demo
The UPDATE action of the ON DUPLICATE KEY clause will only be executed if the row being inserted would cause the violation of a UNIQUE constraint. That means there needs to be a primary key or a unique index on the table.
If you want to modify existing rows, you'd really want to use an UPDATE statement.
To change the value in a column of existing rows, replacing 'oldvalue' with 'newvalue', you could do something like this:
UPDATE mytable
SET col1 = 'newvalue'
WHERE col1 = 'oldvalue'