Get the id of a row when UNIQUE KEY is violated - mysql

I have a table user. It has columns id and email.
USER TABLE
id | email
1 | xxx#gmail.com
2 | yyy#gmail.com
The id is a PRIMARY KEY AUTO_INCREMENT and the email is an UNIQUE KEY.
When I insert a new row in the table and there is a DUPLICATE KEY exception thrown. I want to fetch the id on which the DUPLICATE KEY exception was thrown.
Right now I am doing this -
BEGIN
DECLARE EXIT HANDLER FOR 1062
BEGIN
SELECT id
INTO id
FROM user
WHERE email = 'xxx#gmail.com';
END;
INSERT INTO user
(email)
VALUES
('xxx#gmail.com');
SELECT LAST_INSERT_ID() INTO id;
END;
I want to know if there is a better way to do this. That is to avoid scanning the table again to get the id for which it had already scanned to check the uniqueness of the email.

In scaning by UNIQUE KEY BTREE is used so it's quite fast.
Don't you want check for existing of value by yourself in additional select query

Use INSERT ... ON DUPLICATE KEY UPDATE, then get the autoincremented id as usual:
If a table contains an AUTO_INCREMENT column and INSERT ... ON DUPLICATE KEY UPDATE inserts or updates a row, the LAST_INSERT_ID() function returns the AUTO_INCREMENT value. Exception: For updates, LAST_INSERT_ID() is not meaningful prior to MySQL 5.1.12. 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;

Related

Error: Duplicate entry '1' for key 'students.PRIMARY' Error Code: ER_DUP_ENTRY

CREATE TABLE IF NOT EXISTS students (
student_id INT,
name VARCHAR(24),
major VARCHAR(24),
PRIMARY KEY(student_id)
);
SELECT * FROM student;
INSERT INTO students VALUES(1,'Jack','Biology');
You're specifying the primary key (student_id) and from the error it already exists. You have a few options:
Don't specify the primary key. It should be set to autoincrement anyway, assuming that this is the primary table that students are entered into, and from the name of the table (students) it seems like it is. Then the query will be:
INSERT INTO students VALUES('Jack','Biology');
and then the table will autoincrement the primary key to the next pointer.
Use INSERT IGNORE. This will silently fail if you try to insert a student ID that already exists (or on any query that violates unique keys).
INSERT IGNORE INTO students VALUES(1, 'Jack','Biology');
This will not cause table changes, but it will also not cause an error that interrupts the script, and it will insert any rows that don't fail, say if you had multiple values inserted. The plain INSERT will fail for the entire list, not just the erroneous value.
Use ON DUPLICATE KEY UPDATE. This will update a list of values if it encounters a duplicate key.
INSERT INTO students VALUES(1, 'Jack','Biology')
ON DUPLICATE KEY UPDATE name = values(name), major = values(major);
In this case, you will change the values in the table that match the key. In this case, whichever student is student_id 1 will have its name and major updated to the supplied values. For instance, let's say that Jack changed his major to Chemistry. This would update student_id 1 to Jack, Chemistry and reflect his new major.
Use REPLACE INTO. I avoid this one. It is similar to ON DUPLICATE KEY UPDATE, but it removes the old entry and replaces it with a new one with a new ID. This can cause you problems with foreign keys, and also if you have a small primary key and you constantly replace into it, you can end up with a primary id that's bigger than the limits you set.
Well, your student_id is primary key, clearly that table is already exist with some data with student_id=1 hence you cannot insert another row with the same primary key value.

Reached maximum limit of primary key and deleted all records from table but still can't insert the record

I have a table in which I took two field one is id that is primary key with Auto Increment attribute (tinyint) and another one is name (varchar(20)).
id tinyint(4) NOT NULL AUTO_INCREMENT, name varchar(20) NOT NULL,
PRIMARY KEY (id)
after that I have insert the values in table from 1 to 127 (max limit of tinyint). Now If I try to insert the record in table it gives error because I have reached at max limit of tinyint. I am fine with it. But If I delete all the records and table is empty then also I can't insert any record. I know I can use truncate here that will reset the primary key. But My question is here that why mysql doesn't insert the any available value(from 1 to 127) for primary key and If I manually insert the value for id from 1 to 127 it works.
insert into `new table` (id,name) values(1,'blahblahblah') Working
insert into `new table` (name) values('blahblahblah') Not working
If I have a application with large database and I come this situation and any record insertion can fail in future then how can I know before occurred this.
Is there any way by which I can insert the record(in empty table by delete all records) without truncating the table.
Sorry for my poor English.
Thanks
Mysql saves your AUTO_INCREMENT counter in its INFORMATION_SCHEMA table.
I don't know which version you're using but you should read the docs about it.
As you can read here, you can set the number you want using
ALTER TABLE tablename AUTO_INCREMENT = 1;

Output primary key after insert a row in Mysql

I have created a trigger to help me to make the primary key when I insert a row. I want to get the primary key I just insert. But because the primary key is not auto_increment I cannot use
SELECT LAST_INSERT_ID();
So how can I get the primary key?
Here is the trigger
CREATE TRIGGER before_insert_user_info
BEFORE INSERT ON USER_INFO
FOR EACH ROW
SET new.uID = CONCAT('U', ((SELECT MAX(CAST(SUBSTRING(uID, 2, length(uID)) AS UNSIGNED)) FROM USER_INFO)+1));
And here is the insert
INSERT INTO USER_INFO(name) VALUES ('Peter');
It is kind of unusual to rely on a trigger to generate a primary key. There is no way to retreive data back from a trigger (e.g. it has no return value). But you can reuse your tigger's logic to retreive the generated value:
INSERT INTO user_info VALUE (#newUID, ...);
SELECT MAX(CAST(SUBSTRING(#newUID, 2, LENGTH(#newUID)) AS UNSIGNED)) AS last_insert_id
FROM user_info; -- this is the generated value
Wrap these two statements in a transaction to make sure a new user is not inserted in between.
As an alternative, I would create another INT AUTO_INCREMENT column, so that you can retreive your new row after insertion with LAST_INSERT_ID();
And while we are at it, I would make this new field the (surrogate) primary key. The same trigger could still generate the "public" user ID, but then we would be back to a more usual architecture.
Last food for thoughts: do you really need to store your user ID's with the U prefix? Perhaps you could just store a plain INT value, and preppend the U on selection.

Can I use INSERT INTO ... On DUPLICATE KEY without by using auto_increment value?

I am trying to write a query to check if a record exists (based on couple of clause and not unique identifier) if such a search return records then I need to update all the found records if nothing found then I need to INSERT a record. Note that I can't use IF EXISTS because I am trying to make a query for a client side script and not a server side. So I came a cross the idea of INSERT INTO .... ON DUPLICATE KEY
Can I do this without knowing the row key identifier? So if I find a record where accountid = 17 and name = 'Mike' then update it to make the name 'Mike A' if there is no record with these 2 clause then insert a record.
This is an attempt that is giving me a syntax error
INSERT INTO test (name, accountid) VALUES ('Mike', 17)
ON DUPLICATE KEY
UPDATE test SET name='Mike A' WHERE name ='Mike' AND accountid = 17
Can this method handle what I am trying to do? If yes then can you please correct my syntax?
Thank you
The only way you can get this to work is if you have a primary key or unique constraint on the fields. From the documentation:
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that
would cause a duplicate value in a UNIQUE index or PRIMARY KEY, an
UPDATE of the old row is performed. For example, if column a is
declared as UNIQUE and contains the value 1, the following two
statements have identical effect:
create table test (name varchar(100), accountid int);
insert into test values ('Mike', 17);
alter table test add unique (name, accountid);
insert int test (name, accountid) values ('Mike', 17)
on duplicate key update name='Mike A';
SQL Fiddle Demo
Without the unique key, it will insert a duplicate record.

INSERT ON DUPLICATE KEY UPDATE with last_insert_id()

im trying to create a function
CREATE FUNCTION `func`(param1 INT, param2 INT, param3 TEXT) RETURNS int(11)
BEGIN
INSERT INTO `table1` (`column1`, `column2`, `column3` )
VALUES (param1, param2, param3)
ON DUPLICATE KEY
UPDATE `time_stamp` = UNIX_TIMESTAMP();
RETURN last_insert_id();
END
this would insert into a table a row if it doesn't exist but otherwise update it.
Notice that i returned last_insert_id() which would be correct if the function would insert otherwise would be unpredictable if it updates.
I know the alternative to solving this is using separate SELECTS and identify if it exists; if it exists retrieve the id and update using that id; otherwise just do a plain INSERT.
Now my question: Is there any alternative to doing 2 sql statements as opposed to what i'm doing now?
EDIT 1
Addendum:
there is an auto incremented index.
All of the values to be inserted are unique
I'd rather not alter the index since it is being referred in another table..
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;
Found it on this link. I've never tried it though, but it might help you.
EDIT 1
You might want to check out REPLACE:
REPLACE INTO table1 (column1, column2, column3) VALUES (param1, param2, param3);
This should work for tables with correct PRIMARY KEY/UNIQUE INDEX.
In the end, you'll just have to stick with:
IF (VALUES EXISTS ON TABLE ...)
UPDATE ...
SELECT Id;
ELSE
INSERT ...
RETURN last_insert_id();
END IF
Just in case anyone shows up here from Google, I ran into a problem where ON DUPLICATE KEY UPDATE kept triggering the same wrong value.
When inserting a user with only a first name and last name, it didn't AUTO_INCREMENT the primary key. The reason is we have a users table with a unique constraint on the username, but it has a default value of ''. So when you insert a user without a username, it triggers it to update the duplicate value of that username, and that random account kept getting returned as the correct one.
The solution is to make sure that only NULL is the default value for a unique key in a table that also has a separate auto-increment primary key, or that you do generate a unique value for the unique constraint.