Hi i have asked a question about how to transfer the sql code from Postgresql to Mysql.
Thanks to the kindly help i am now able to create the table. Now i have a following question of the query to transfer again from Postgresql to Mysql.
Create the table
CREATE TABLE public.`user` (
id varchar(10) NOT NULL,
chat_id varchar(10) NULL,
state INT NOT NULL,
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
The query i'd like to transfer to mysql:
After insert a row of data, check if id has conflict. if we get a conflict we update chat_id and state
sql = '''INSERT INTO public.`user`
(id, chat_id, state)
VALUES(%s, %s, 1)
ON CONFLICT(id) DO UPDATE
SET chat_id = EXCLUDED.chat_id, state = EXCLUDED.state;
'''
PostgreSQL's ON CONFLICT is close to MySQL's ON DUPLICATE KEY UPDATE.
But your query do the next: if entered id value is absent in the table then the row is inserted, if it is present then old row state is preserved. For to do the same in MySQL you may use more simple
INSERT IGNORE INTO public.`user` (id, chat_id, state)
VALUES(%s, %s, 1);
I.e. if some error (including duplicate violation) detected then simply ignore the values to be inserted. Pay attention - any error, not only duplicate violation, will be ignored.
If it is not safe for you then use ODKU:
INSERT IGNORE INTO public.`user` (id, chat_id, state)
VALUES(%s, %s, 1)
ON DUPLICATE KEY UPDATE id=id;
In MySQL in ODKU clause only explicitly updated columns values are altered (rather than ON CONFLICT) - so id reassign to the same value is an analog of "ignore new values". Of course you may use ON DUPLICATE KEY UPDATE chat_id=chat_id, state=state, no difference.
I was trying to write an upsert, and when I run these two queries sequentially:
// The numbers here are arbitrary, but id matches one already existing in db.
SET #id = 1069, #exportid = null, #photoid = 11223344;
INSERT INTO student (id_number, exportid, photoid) VALUES (#id, #exportid, #photoid)
ON DUPLICATE KEY UPDATE exportid = #exportid, photoid = #photoid;
and it hits the update and makes some changes, I get "2 rows affected". Why isn't it just one (If it hits the insert I get 1 row affected as expected)?
The CREATE statement for the table, with a bunch of non-key columns redacted:
CREATE TABLE `demo`.`student` (
`id_number` varchar(15) NOT NULL DEFAULT '',
`exportid` varchar(20) DEFAULT NULL,
`photoid` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id_number`),
KEY `EXPORTID` (`exportid`),
KEY `NAME` (`last_name`,`student`,`id_number`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if
the row is inserted as a new row, 2 if an existing row is updated, and
0 if an existing row is set to its current values.
from the official docs
Is it possible to update only a single field with ON DUPLICATE KEY UPDATE in a table with multiple fields?
If I have a table with three fields; key, cats, dogs where key is the primary key is it possible to update a record on duplicate key, changing only one field, (for my example cats) without changing the value in the other non-key fields (dogs). This is without knowing what the value of dogs from outside of the database at the time of insertion (i.e. I have a variable holding cats value, but not one holding dogs value)
INSERT INTO `myTable` (`key`,`cats`) VALUES('someKey1','Manx') ON DUPLICATE KEY UPDATE `cats` = 'Manx';
At the moment when I run something like this and the key already exists in the table dogs is set to NULL even when it had a value previously.
Gordon is right, it does not work the way I described. If you see this, it is not caused by the ON DUPLICATE UPDATE statement, but something else. Here is the proof:
CREATE TABLE IF NOT EXISTS `myTable` (
`key` varchar(20) NOT NULL default '',
`cats` varchar(20) default NULL,
`dogs` varchar(20) default NULL,
PRIMARY KEY (`key`)
)
The run
INSERT INTO `myTable` (`key`, `cats`, `dogs`) VALUES
('someKey1', NULL, 'jack-russell');
Then run
INSERT INTO `myTable` (`key`,`cats`) VALUES
('someKey1','Manx') ON DUPLICATE KEY UPDATE `cats` = 'manx';
Then check the table
I think you should try to UPSERT.
Please examine this:
INSERT INTO `item` (`item_name`, items_in_stock) VALUES( 'A', 27)
ON DUPLICATE KEY UPDATE `new_items_count` = `new_items_count` + 27
MySQL UPSERT
I have to update a table with the following structure:
CREATE TABLE `eav_entity_attribute` (
`entity_attribute_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Entity Attribute Id',
`entity_type_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Entity Type Id',
`attribute_set_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Set Id',
`attribute_group_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Group Id',
`attribute_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Id',
`sort_order` smallint(6) NOT NULL DEFAULT '0' COMMENT 'Sort Order',
PRIMARY KEY (`entity_attribute_id`),
UNIQUE KEY `UNQ_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_SET_ID_ATTRIBUTE_ID` (`attribute_set_id`,`attribute_id`),
UNIQUE KEY `UNQ_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_GROUP_ID_ATTRIBUTE_ID` (`attribute_group_id`,`attribute_id`),
KEY `IDX_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_SET_ID_SORT_ORDER` (`attribute_set_id`,`sort_order`),
KEY `IDX_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_ID` (`attribute_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Eav Entity Attributes'
Above table contains a single row:
INSERT INTO `eav_entity_attribute`
(`entity_attribute_id`, `entity_type_id`, `attribute_set_id`, `attribute_group_id`, `attribute_id`, `sort_order`)
VALUES
(32758, 4, 224, 3423, 5171, 12)
I'm running an automatic import procedure, which will read an external source of data and write into this table.
This import runs multiple times and, therefore, sometimes the same data is imported several times. In such case, the procedure simply overwrites the old data with the new one, even when the new one is identical to the old. The condition where the same data exists is handled with an ON DUPLICATE KEY UPDATE clause. This works almost perfectly, except on this specific table.
On this table, when the procedure attempts an UPDATE, I receive a "Duplicate key" message, which I can't explain. I debugged the code, and this is the query that fails (extracted from the INSERT..ON DUPLICATE KEY):
UPDATE eav_entity_attribute
SET
`attribute_group_id` = 3423
,`attribute_id` = 5171
,`attribute_set_id` = 223
,`entity_type_id` = 4
,`sort_order` = 320
WHERE
(`attribute_group_id` = 3423) AND
(`attribute_id` = 5171)
The error is the following:
Error Code: 1062. Duplicate entry '3423-5171' for key 'UNQ_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_GROUP_ID_ATTRIBUTE_ID'
I know that the pair 3423-5171 already exists, but the UPDATE would replace these values with themselves, not create a new entry. I'm quite confused about the cause of this issue, any suggestion would be very welcome. Thanks.
Update - New finding
I got some sort of "inspiration" and I made an experiment. I removed the Unique constraint involving on (attribute_set_id,attribute_id) (note, this is not the one in the error) and I ran the INSERT..ON DUPLICATE query. It worked perfectly.
Mine is a conjecture, but this is what I think: the data I'm trying to write to the table clashes with two constraints:
UNIQUE(attribute_set_id,attribute_id)
UNIQUE(attribute_group_id,attribute_id)
The INSERT fails, presumably because of the duplication error raised by the first constraint. This triggers the UPDATE, which uses the first constraint as the implicit WHERE clause. My speculation is that, in such case, the first constraint is somehow ignored, but the UPDATE trips over the second, which didn't get involved earlier.
This still doesn't seem, to me, a valid reason for an UPDATE which replaces something with itself to raise a duplicate entry error, but it may shed some light on the logic behind it.
Second Update
I found out that the table I was testing against actually contains a lot of rows (I forgot to disable the filtered view) resulting from the successful import of other data. However, the "duplicate candidate" is still unique in the set.
I confirm what posted in the comments, when the table contains only that rows, the INSERT..ON DUPLICATE works, as well as the UPDATE alone. Now I'm wondering why does the table get messed up when there is more data in it, since we are still talking about a single unique row being updated with the same data.
Third Update - Found the root cause
I finally found out the reason why the UPDATE fails, now I have to find out how do I get in such condition.
The clue was my conjecture in the first update. Simply, I have two very similar rows (please note I'm using different values as I started from a clean database).
row,entity_attribute_id,entity_type_id,attribute_set_id,attribute_group_id,attribute_id,sort_order
1,16919, 4, 120, 1746, 80, 1
2,16649, 4, 119, 1744, 80, 210
Here's what happens:
The INSERT attempts to insert a row with the following values: 120, 4, 1744, 80, 54.
This triggers the "duplicate key", since the values 120, 80 are a duplicate for the fields attribute_set_id, attribute_id (row 1).
MySQL then tries the UPDATE, which becomes as follows:
UPDATE table
entity_type_id = 4
,attribute_group_id = 1744
,sort_order = 54
WHERE
(attribute_set_id = 120) AND (attribute_id = 80)
This time, the UPDATE fails because the values 1744,80 are violate the constraint on the pair attribute_group_id, attribute_id, found in row 2.
In summary
The INSERT fails because row 1 has the same values for the key attribute_set_id, attribute_id.
The UPDATE fails because row 2 has the same values for the key attribute_group_id, attribute_id.
Solution
I will have to review the whole import procedure, as, in theory, none of such duplicates should arise. MySQL is doing its job fine, it's the database that is complicated.
Thanks for all the suggestions.
Try not to update key values within UPDATE clause of INSERT ... ON DUPLICATE KEY UPDATE. It is strange to ask MySQL to change key values if a record with these key values already exist, so, unexpected behavoiur of MySQL is not surprising.
In MySQL, you can insert a row and update the 'last insert ID' at the same time. I'm using this trick to be able to insert items conditionally (uniqueness) and still get the unique ID in all cases.
The code below works. The problem is that the ON DUPLICATE KEY statement also updates the Auto_increment value. Is it possible to avoid that?
CREATE TABLE T(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
X VARCHAR(64) NOT NULL UNIQUE
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
INSERT INTO T(X) VALUES ('x') ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id);
SELECT LAST_INSERT_ID();
INSERT INTO T(X) VALUES ('x') ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id);
SELECT LAST_INSERT_ID();
Now we have one entry with id=1. However, the next entry will have id=3 since the Auto_increment value was updated when the second INSERT failed. This can be checked as follows:
SELECT Auto_increment FROM information_schema.tables WHERE table_name = 't'
AND table_schema = DATABASE();
Q: Is it possible to use this trick (or equivalent) and keep the Auto_increment value? Obviously, in this case, it doesn't need to get updated.