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.
Related
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.
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.
I am trying to check if a session exists for a customer so that I can either update the session with new session details or insert a session for a customer. I am using the statement below:
INSERT INTO sessions (customerid, productlist, date)
VALUES('33', '{"68":1,"72":1}', '2016-03-03 13:54:56')
ON DUPLICATE KEY UPDATE customerid=VALUES(customerid)
When I run this, the statement inserts a session for customer even if a session already exists.
ON DUPLICATE KEY UPDATE requires an UNIQUE INDEX on the table. It allows updating the already existing row when the INSERT will fail because of the UNIQUE INDEX.
The candidate for UNIQUE INDEX in your sessions table is customerid. Do you have such an index?
Anyway, the query you posted doesn't make any sense. ON DUPLICATE KEY UPDATE kicks in when you want to insert a new row and the value you want to put in customerid already exists in the table. The UNIQUE INDEX prevents the insertion and ON DUPLICATE KEY UPDATE allows the updating of some of the other columns of the existing row.
When customerid is the UNIQUE INDEX, customerid=VALUES(customerid) is a no-op.
What you probably want is:
INSERT INTO sessions (customerid, productlist, date)
VALUES('33', '{"68":1,"72":1}', '2016-03-03 13:54:56')
ON DUPLICATE KEY UPDATE productlist=VALUES(productlist), date=VALUES(date)
The SQL statement to make customerid an UNIQUE INDEX of table sessions is:
ALTER TABLE `sessions`
ADD UNIQUE INDEX `customerid` (`customerid`)
Or, even better, make is the PRIMARY KEY of the table (if the table doesn't already have one:
ALTER TABLE `sessions`
ADD PRIMARY KEY (`customerid`)
Make sure you create an UNIQUE key by using: customerid and pdoructlist columns.
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.
I've been reading up on how to use MySQL insert on duplicate key to see if it will allow me to avoid Selecting a row, checking if it exists, and then either inserting or updating. As I've read the documentation however, there is one area that confuses me. This is what the documentation says:
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
The thing is, I don't want to know if this will work for my problem, because the 'condition' I have for not inserting a new one is the existence of a row that has two columns equal to a certain value, not necessarily that the primary key is the same. Right now the syntax I'm imagining is this, but I don't know if it will always insert instead of replace:
INSERT INTO attendance (event_id, user_id, status) VALUES(some_event_number, some_user_id, some_status) ON DUPLICATE KEY UPDATE status=1
The thing is, event_id and user_id aren't primary keys, but if a row in the table 'attendance' already has those columns with those values, I just want to update it. Otherwise I would like to insert it. Is this even possible with ON DUPLICATE? If not, what other method might I use?
The quote includes "a duplicate value in a UNIQUE index". So, your values do not need to be the primary key:
create unique index attendance_eventid_userid on attendance(event_id, user_id);
Presumably, you want to update the existing record because you don't want duplicates. If you want duplicates sometimes, but not for this particular insert, then you will need another method.
If I were you, I would make a primary key out of event_id and user_id. That will make this extremely easy with ON DUPLICATE.
SQLFiddle
create table attendance (
event_id int,
user_id int,
status varchar(100),
primary key(event_id, user_id)
);
Then with ease:
insert into attendance (event_id, user_id, status) values(some_event_number, some_user_id, some_status)
on duplicate key
update status = values(status);
Maybe you can try to write a trigger that checks if the pair (event_id, user_id) exists in the table before inserting, and if it exists just update it.
To the broader question of "Will INSERT ... ON DUPLICATE respect a UK even if the PK changes", the answer is yes: SQLFiddle
In this SQLFiddle I insert a new record, with a new PK id, but its values would violate the UK. It performs the ON DUPLICATE and the original PK id is preserved, but the non-UK ON DUPLICATE KEY UPDATE value changes.