Is there a way to restrict "ON DUPLICAYE KEY UPDATE" to only trigger if the duplicate key is the PRIMARY KEY of the table? (and not if the conflict is generated by a UNIQUE KEY)
For example in the following table:
CREATE TABLE users (
id INT(16) UNSIGNED AUTO_INCREMENT,
username VARCHAR(255) NOT NULL UNIQUE,
PRIMARY KEY (id),
UNIQUE (username)
);
I would like to trigger the update only if the id column generate the conflict, and throw an error as usual in case the conflict happened because of the unique key username.
Edit:
I'm working on a very simple PHP framework. Previously I had a single method save() that discriminated between INSERT and UPDATE based on the presence of the id property on the object on which it was called.
Now I rewrote this method using the INSERT INTO ... ON DUPLICATE KEY UPDATE query, but when I try to insert (for example) a user with an already existing username value, it updates that user instead of throwing an error.
I know this is the correct behaviour, I just wanted to know if there's a way to achieve the same result only on the PRIMARY KEY.
on duplicate key triggers for both primary keys and unique keys.
In your case, the primary key is an auto-incremented column, so you should not be inserting a value. Period.
Hence, you can get the behavior you want by simply not including the on duplicate key clause and leaving out the id from the insert.
Related
I've been looking at other resources and am just getting a bit confused. I'd like to relate an example to my problem.
I have a game server which stores a unique id from steam in a database, and along with this has a column for specific permissions to that user. E.g id: 712309123810 permission: default
What I want to achieve is sending data from a form; $Id and $permission are posted. Insert this data into the database under columns for example sake; 'Id' and 'permission'. I can do this, what I am having issues is understanding how to UPDATE only the $permission column if the $id already exists in the db.
I have read about ON DUPLICATE KEY UPDATE , but am confused about how to correctly utilize it. I am fairly new to mysql.
Thanks for your time.
The on duplicate key fires when the insert part of the statement violates a unique constraint (in your case - the primary key on id). So, to put it all together:
INSERT INTO mytbale (id, permissions)
VALUES (:id, :permissions)
ON DUPLICATE KEY UPDATE permissions = :permissions
It's explained rather well by the manual:
http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
Your query might be something like:
INSERT INTO myTable (id, permissions) VALUES (712309123810, "default")
ON DUPLICATE KEY UPDATE permissions = "default";
This requires that the table contains a unique or primary key on the id column.
Normally, if you attempt to insert a new row that would create a duplicate value for a unique or primary key, it is an error. Using ON DUPLICATE KEY UPDATE changes that: instead, your insert transforms into an update.
The example query I gave will insert a new record if none with that id exists, or it will update the permissions of the existing one.
Typically, an id can have multiple permissions. If so, you don't want to overwrite the permissions; you want to accumulate them. If this is the case, you might need junction table to handle this:
create table UserPermissions (
UserPermissionsId int auto_increment primary key,
UserId int not null,
PermissionId int not null,
constraint fk_UserPermissions_UserId foreign key UserId references Users(UserId),
constraints fk_UserPermissions_PermissionId foreign key Permissions references Permissions (PermissionId)
);
If a user has only one permission that gets overwritten, then on duplicate key update is appropriate.
In MySQL, is there any way to obtain a primary key value generated by a before-insert trigger?
I know that select last_insert_id() can return the first value of an auto_increment column from a previous insert, but I can't seem to get it to work with a trigger-generated primary key.
There is no other unique key on my table, so I won't be able to perform a subsequent select to determine the generated primary key by just using data that was used in the insert.
I´m creating a database addrees and I want to know what I need to set in Mysql to don´t store repeat values?
Like
Addrees 1 ("teste",1,new york,eua);
Addrees 2 ("teste",1,new york,eua);
If this happen my database will not store.
So what I need to do?
To alter an already existing table, run this MySQL command:
alter table yourtablename add unique index(firstcolumn, secondcolumn, thirdcolumn, fourthcolumn);
That'll add the unique constraint to the specified columns. Here's how to specify such a constraint in the CREATE TABLE.
CREATE TABLE buyers (
buyer_id INT UNSIGNED NOT NULL,
first_name CHAR(19) NOT NULL,
last_name CHAR(19) NOT NULL,
age SMALLINT NOT NULL,
post_code SMALLINT NOT NULL,
UNIQUE idx_flname_age (first_name,last_name,age)
);
The primary key constraint will do this too, as mentioned by #Ajeesh
EDIT:
As per the suggestion in the comment, if you want to avoid errors generated by this unique constraint, you have three good options:
INSERT IGNORE
and
INSERT...ON DUPLICATE KEY UPDATE
and
REPLACE
INSERT IGNORE will not do anything if the insert violates the unique constraint, except log a harmless warning. The table will be left as is, and no error would be reported. This may be desireable in some cases.
More commonly is the second option, ON DUPLICATE KEY UPDATE, which says "Well, if the key already exists, then update that key's row like this instead."
And lastly is REPLACE, which will, if the key already exists, delete the row, then do an INSERT as normal. If the key did not exist previously, it will simply act as an INSERT.
This stack overflow answer has some examples.
"INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE"
You need to call these fields a UNIQUE_KEY
To make a column to be distinct you need to have Primary Key constraint/Unique Key. Primary key is used for relating one table with another and it's values should not be NULL. But in your case you can have Unique constraint to store only unique/distinct values.
How would you implement the following?
I would like to insert data to mysql tables. Let's imagine there are two tables where a foreign key relation exists. First, i insert a row that has a primary key that should be inserted as a foreign key to one of the rows to the other table. So when i would like to insert the foreign key and it's related data, i have to know the primary key of the related row in the other table. As i am a beginner, my solution would be the following: I would insert a field value with a particular data to the original table so that the inserted value could be used to retrieve the primary key with a SELECT, and then insert the retrieved primary key as the foreign key to the related rows of the other table.
Although I don't know a better solution, I think this would be a very clumsy way to implement this logic. There must be a better way of doing this.
Your solution won't work because if you are inserting not unique data, you may not retrieve the appropriate primary key. MySQL offers LAST_INSERT_ID() function for this. Just insert row into your primary key table and then use SELECT LAST_INSERT_ID(). It returns last primary key value inserted into your original table (last insert query) and now you can use it as foreign key in related table.
I have a table with a unique key for two columns:
CREATE TABLE `xpo`.`user_permanent_gift` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`fb_user_id` INT UNSIGNED NOT NULL ,
`gift_id` INT UNSIGNED NOT NULL ,
`purchase_timestamp` TIMESTAMP NULL DEFAULT now() ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `user_gift_UNIQUE` (`fb_user_id` ASC, `gift_id` ASC) );
I want to insert a row into that table, but if the key exists, to do nothing! I don't want an error to be generated because the keys exist.
I know that there is the following syntax:
INSERT ... ON DUPLICATE KEY UPDATE ...
but is there something like:
INSERT ... ON DUPLICATE KEY DO NOTHING
?
Yes, use INSERT ... ON DUPLICATE KEY UPDATE id=id (it won't trigger row update even though id is assigned to itself).
If you don't care about errors (conversion errors, foreign key errors) and autoincrement field exhaustion (it's incremented even if the row is not inserted due to duplicate key), then use INSERT IGNORE like this:
INSERT IGNORE INTO <table_name> (...) VALUES (...)
HOW TO IMPLEMENT 'insert if not exist'?
1. REPLACE INTO
pros:
simple.
cons:
too slow.
auto-increment key will CHANGE(increase by 1) if there is entry matches unique key or primary key, because it deletes the old entry then insert new one.
2. INSERT IGNORE
pros:
simple.
cons:
auto-increment key will not change if there is entry matches unique key or primary key but auto-increment index will increase by 1
some other errors/warnings will be ignored such as data conversion error.
3. INSERT ... ON DUPLICATE KEY UPDATE
pros:
you can easily implement 'save or update' function with this
cons:
looks relatively complex if you just want to insert not update.
auto-increment key will not change if there is entry matches unique key or primary key but auto-increment index will increase by 1
4. Any way to stop auto-increment key increasing if there is entry matches unique key or primary key?
As mentioned in the comment below by #toien: "auto-increment column will be effected depends on innodb_autoinc_lock_mode config after version 5.1" if you are using innodb as your engine, but this also effects concurrency, so it needs to be well considered before used. So far I'm not seeing any better solution.
Use ON DUPLICATE KEY UPDATE ...,
Negative : because the UPDATE uses resources for the second action.
Use INSERT IGNORE ...,
Negative : MySQL will not show any errors if something goes wrong, so you cannot handle the errors. Use it only if you don’t care about the query.