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.
Related
I removed my record ID while I'm using unique hashes as a primpary key. This primary key obviously cannot auto increment.
Now my question is how to retreive the last inserted primary key? MySQL returns 0 on LAST_INSERT_ID() while it's not an auto increment column.
The fact
There's no equivalent to LAST_INSERT_ID() returning a non integer value.
One can simply
The easy approach
Add an integer column which can either be auto incremented or non auto incremented.
To have it auto incremented correctly one has at least to implement an algorithm in MySQL itself or with a language of their choice to fill the existing records with the new IDs.
The more complex approach
https://stackoverflow.com/a/53481729/2323764 (#kellymandem)
Add a second table managing the ID and triggered by the origin table without IDs.
One cannot
I found this very promising Q/A.
Is there a way to get last inserted id of a NON - auto incremented column in MySQL?
It's mentioned there to use LAST_INSERT_ID() in the INSERT statement already.
But
INSERT INTO `table` ( `non_integer_column` ) VALUES ( LAST_INSERT_ID( 42 ) );
SELECT LAST_INSERT_ID( );
-> 42
INSERT INTO `table` ( `non_integer_column` ) VALUES ( LAST_INSERT_ID( 'a0b1c2d3e4f5' ) );
SELECT LAST_INSERT_ID( );
-> 0
Non integer values will be ignored.
I think your problem could best be solved by creating a new table and a trigger to keep track of the newly inserted hash values in the main table.
For example
CREATE TABLE test_table (
hash VARCHAR(30) NOT NULL PRIMARY KEY,
fullname VARCHAR(120) NOT NULL
);
CREATE TABLE hash_tracker(
hash VARCHAR(30) NOT NULL,
created_at DATETIME NOT NULL
);
DELIMITER $$
CREATE TRIGGER `test_trigger`
AFTER INSERT ON `test_table`
FOR EACH ROW
BEGIN
INSERT INTO hash_tracker VALUES (NEW.`hash`, NOW());
END$$
DELIMITER ;
Then after each insert on my test_table, i can run the following query
SELECT hash FROM hash_tracker ORDER BY created_at DESC LIMIT 1;
to get the most recently inserted hash.
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
We have a table:
id int(11) auto_increment
name varchar(255)
auto_increment equals 1.
Insert row:
INSERT INTO `projects` ( `id` , `name`) VALUES ('350', 'project one');
Now auto_increment equals 351.
Update row:
UPDATE `projects` SET `id` = '351' WHERE `id` = 350 LIMIT 1 ;
auto_increment still equals 351. And we get error if try to insert a row:
#1062 - Duplicate entry '351' for key 1
How we can see INSERT changes auto_increment and UPDATE not changes auto_increment.
My goal is to update row and set id greater then auto_increment.
How to do it?
First of all why are you trying to set the auto increment value? Just let it do its job (clue - it is automatic).
So the best solution is when you insert a row let the auto increment chose the appropriate value for you and let that value be an invariant for that rows life time.
Otherwise just remove the auto_increment bit from the table definition and implement an appropriate system yourself.
So I have a table like this:
create table `test` (
`testId` int(11) not null auto_increment,
`text` varchar(10) not null default '',
primary key(`testId`),
unique(`text`)
) engine=innodb;
My insert would be
insert into test (text) values ('a');
insert into test (text) values ('b');
insert into test (text) values ('a');
the 3rd insert will fail, but I want it to return the testId for the duplicate (for 'a').
Is this possible without writing a second query?
You can't do this in an INSERT query because the INSERT does not return any rows.
When an INSERT fails because of a duplicated key - normally the thing that built the query knows what data it sent, so it could use this.
You may be able to achieve what you want by using 12.2.5.3. INSERT ... ON DUPLICATE KEY UPDATE
If a table contains an AUTO_INCREMENT
column and INSERT ... UPDATE inserts a
row, the LAST_INSERT_ID() function
returns the AUTO_INCREMENT value. If
the statement updates a row instead,
LAST_INSERT_ID() is not meaningful.
However, you can work around this by
using LAST_INSERT_ID(expr). Suppose
that id is the AUTO_INCREMENT column.
To make LAST_INSERT_ID() meaningful
for updates, insert rows as follows:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;
There are two ways of doing this. If you just want to replace the existing data, you can use
REPLACE INTO <table_name> VALUES <values>
That is the simplest thing. But if you just want to check whether the data exist, you can first, do this
SELECT COUNT(*) FROM <table> WHERE <field>='<field_value>
If exists, query returns more than 0.
Hope this helps.
Is there a way to make this statement into one? The basic idea is to insert a tag name if it doesnt exist and to retrieve the primary key for my next statement. title column is unique.
INSERT INTO `tag_name` (`count`, `title`)
SELECT 0, #title FROM DUAL
WHERE not exists
(SELECT * FROM `tag_name` WHERE `title` = #title LIMIT 1);
If rows affect >0 then use last_insert_rowid(), otherwise run this statement
SELECT id from FROM `tag_name` WHERE `title` = #title
--- here is a test
CREATE TABLE test (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, data int unique);
//insert into test(data) select 5;
You can use
insert into ... on duplicate update
this is insert row and when key was duplicate then update it.also u can use:
insert into on duplicate update field1=field1
this will ignore on duplicate !
you can use the MySql specific Replace syntax. Check here for more information.