Update if exists, otherwise insert (without unique keys) - mysql

I have a table that is created like this:
'CREATE TABLE `boss_kills` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`characterid` int(11) DEFAULT NULL,
`mobid` int(11) DEFAULT NULL,
`amount` int(11) NOT NULL DEFAULT ''0'',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=25 DEFAULT CHARSET=latin1'
Goal: I'm trying to create a system where a player kills a boss in the game and it records the boss's ID and the player's ID in the table. I want to be able to write one query where it updates if the player is already logged with the specific boss and inserts if he or she isn't.
Research: I did a lot of research online and people suggest the INSERT INTO ... ON DUPLICATE KEY UPDATE, but that only works if you either know your primary key or have a unique key, none of which I have or know.
Tries: I've tried
IF EXISTS (...) THEN UPDATE (...) ELSE INSERT(...)
and
UPDATE (...) IF ##ROWCOUNT = 0 INSERT INTO (...)
but they don't work. I get syntax errors.
If needed I can provide the errors thrown by the above tries. My current code for trying to update is this (but it throws a SQL syntax error):
Attempt 1:
UPDATE boss_kills
SET amount = amount + 1
WHERE characterid = ? AND mobid = ?
IF ##ROWCOUNT = 0
INSERT INTO boss_kills (characterid, mobid, amount) VALUES (?, ?, 1)
Attempt 2:
IF NOT EXISTS (SELECT id FROM boss_kills WHERE characterid = ? AND mobid = ?)
THEN
INSERT INTO boss_kills VALUES (DEFAULT, ?, ?, 1)
ELSE
UPDATE boss_kills SET amount = amount + 1 WHERE characterid = ? AND mobid = ?

It seems like (characterid, mobid) could make a unique index constraint for your table, thus allowing you to use INSERT ... ON DUPLICATE KEY UPDATE.
Use below script to create your table
CREATE TABLE boss_kills (
id int(11) NOT NULL AUTO_INCREMENT,
characterid int(11) DEFAULT NULL,
mobid int(11) DEFAULT NULL,
amount int(11) NOT NULL DEFAULT 0,
PRIMARY KEY ( id ),
UNIQUE ( characterid, mobid )
) ENGINE=MyISAM AUTO_INCREMENT=25 DEFAULT CHARSET=latin1;
Note that I've removed backticks around your table and column names - they are not necessary.
Inserting a row
INSERT INTO boss_kills (characterid, mobid, amount)
VALUES (?, ?, 1)
ON DUPLICATE KEY UPDATE amount = amount + 1;

Related

mysql bulk update multiple records at once

I have data such as:
id table column add edit delete view
1 vendors city 0 0 0 1
1 vendors state 0 0 0 1
1 vendors zip 0 0 0 1
And i am trying to perform a bulk update with a similar query:
UPDATE user_perms SET add = ?, edit = ?, delete = ?, view = ?
WHERE id = ? AND table_name = ? AND column_name = ?
Without having to loop through a list and run this query X number of times, does MySQL support a way to bulk update in 1 go?
CREATE TABLE STMT:
CREATE TABLE `user_perms` (
`up_id` int unsigned NOT NULL AUTO_INCREMENT,
`id` int unsigned DEFAULT NULL,
`table_name` varchar(255) DEFAULT NULL,
`column_name` varchar(255) DEFAULT NULL,
`add` int unsigned DEFAULT NULL,
`edit` int unsigned DEFAULT NULL,
`delete` int unsigned DEFAULT NULL,
`view` int unsigned DEFAULT NULL,
PRIMARY KEY (`up_id`),
UNIQUE KEY `up_id_UNIQUE` (`up_id`),
KEY `fk_idx` (`id`),
CONSTRAINT `fk_id` FOREIGN KEY (`id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1659 DEFAULT CHARSET=utf8
In your case, the closest thing you could do to update multiple rows is to set the values using CASE expressions:
UPDATE user_perms
SET add = CASE column_name WHEN 'city' THEN ? WHEN 'state' THEN ? WHEN 'zip' THEN ? END,
edit = CASE column_name WHEN 'city' THEN ? WHEN 'state' THEN ? WHEN 'zip' THEN ? END,
delete = CASE column_name WHEN 'city' THEN ? WHEN 'state' THEN ? WHEN 'zip' THEN ? END,
view = CASE column_name WHEN 'city' THEN ? WHEN 'state' THEN ? WHEN 'zip' THEN ? END
WHERE id = ? AND table_name = ?;
It would be even more complicated if you wanted to put both table_name and column_name into the CASE expression.
Frankly, it's easier to just write the loop and do this one row at a time.
If you had a unique key for example comprised of the columns (id, table_name, column_name) so SQL could detect when it was inserting a duplicate row, you could do the following:
INSERT INTO user_perms (id, table_name, column_name, add, edit, delete, view)
VALUES (1, 'vendors', 'city', 0, 0, 0, 1),
(1, 'vendors', 'state', 0, 0, 0, 1),
(1, 'vendors', 'zip', 0, 0, 0, 1)
-- any number of additional tuples follow
ON DUPLICATE KEY UPDATE add = VALUES(add), edit = VALUES(edit),
delete = VALUES(delete), view = VALUES(view);
If this worked, you would not need to delete the rows first. INSERT .. ON DUPLICATE KEY UPDATE is intended to insert a new row if the data you insert does not conflict with an existing row, but if the values you insert do conflict with a unique key on the table, it updates only those columns you set, according to the UPDATE clause. Read the documentation for more details.

How to get auto-increment PK on a multi-row insert in MySql

I need to get back a list of "affected" ids when inserting multiple rows at once. Some rows might already be there, resulting in an update instead.
DDL:
CREATE TABLE `users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`email` varchar(100) NOT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT '1',
`update_time` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
UNIQUE KEY `email` (`email`)
)
Query:
INSERT INTO users (id, email, is_active)
VALUES (NULL, "joe#mail.org", true),
(NULL, "jack#mail.org", false),
(NULL, "dave#mail.org", true)
ON DUPLICATE KEY UPDATE
is_active = VALUES(is_active)
There is a UNIQUE constraint on email.
From what I gathered, LAST_INSERT_ID() would only give me first generated id of the batch. But I wouldn't know how many inserts/updates really took place.
The only way I could come up with is to follow with a second SELECT statement:
SELECT id
FROM users
WHERE email IN ("joe#mail.org", "jack#mail.org", "dave#mail.org")
Is there a better way?

Duplicate entry '111-222' for key 'PRIMARY' when inserting a new value to MySQL database

I have a MySQL table running on AWS RDS with structure like the following:
CREATE TABLE `my_table` (
`col1` int(11) NOT NULL,
`col2` int(11) NOT NULL DEFAULT '0',
`f_name` varchar(45) DEFAULT NULL,
`l_name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`col1`,`col2`),
KEY `idx_col1` (`col1`),
KEY `idx_col2` (`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The query
SELECT * FROM my_table WHERE col1=111 AND col2=222;
returns 0 row.
But when I run an insert query
INSERT INTO my_table
(col1, col2, f_name, l_name)
VALUES (111, 222, 'John', 'Doe')
I got an error saying
Duplicate entry '111-222' for key 'PRIMARY'.
Why does this happen? The table doesn't contain a row with col1=111 and col2=222.
There's already a row with values col1=111, col2=111, f_name='John', and l_name='Doe'. But I don't think this would cause a duplicate entry error.
=========================== EDIT ======================================
There's a trigger that generates the duplicate error. Here's the script to reproduce the error.
# Initialize the tables
CREATE TABLE `my_table` (
`col1` int(11) NOT NULL,
`col2` int(11) NOT NULL DEFAULT '0',
`f_name` varchar(45) DEFAULT NULL,
`l_name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`col1`,`col2`),
KEY `idx_col1` (`col1`),
KEY `idx_col2` (`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `triggered_table` (
`col1` int(11) NOT NULL,
`col2` int(11) NOT NULL DEFAULT '0',
`update_date` bigint(20) DEFAULT NULL,
PRIMARY KEY (`col1`,`col2`),
KEY `idx_col1` (`col1`),
KEY `idx_col2` (`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# Insert the data that cause duplicate error
INSERT INTO triggered_table (col1, col2) VALUES (111, 222);
# Create the trigger
DELIMITER $$
CREATE TRIGGER weird_trigger AFTER INSERT
ON my_table
FOR EACH ROW
BEGIN
INSERT INTO triggered_table
(col1, col2)
VALUES (NEW.col1, NEW.col2);
END$$
DELIMITER ;
# Create the duplicate error
INSERT INTO my_table
(col1, col2, f_name, l_name)
VALUES (111, 222, 'John', 'Doe');
I really don't understand why the developers created the triggered_table table. Why didn't they put update_date column to my_table?
This is so weird.
All you have to do is:
Truncate your table then run (Assuming that you have only a test data but if not, you have to do some backup first)
INSERT INTO my_table
(col1, col2, f_name, l_name)
VALUES (111, 222, 'John', 'Doe')
Now if the error still exists, this is a pretty much problem.
Your error seems like you concatinated col1 and col2 as your primary key ('111-222')
You can try
select * from yourTable where FieldPrimary = '111-222' if it is already exists
The duplicate key error does not come from the my_table table but from the triggered_table table instead. When you add a row in triggered_table for the key (111, 222) and then add a new row in the my_table table (with the same key), your trigger will also try to add a new row with the key (111, 222) in your triggered_table. However there is already such a key in use and you will get the duplicate key error.
Depending on what you want to do with the my_table and triggered_table tables, you might want to change the trigger to use REPLACE INTO instead of INSERT INTO. Or you run a check with SELECT first to see if you need to add a new row or not. After that you can run an UPDATE query to change the value of update_date. But to answer your question, the duplicate key error comes from the duplicate key in the triggered_table table.

MySQL: update a record, on duplicate key leave NEWER one, and delete OLDER one? See inside

There is a table:
CREATE TABLE `mytable` (
`user_id` INT(10) UNSIGNED NOT NULL,
`thing_id` VARCHAR(100) NOT NULL DEFAULT '',
`lock_date` DATETIME NOT NULL,
`lock_id` VARCHAR(36) NOT NULL,
PRIMARY KEY (`user_id`,`thing_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
and some values there:
INSERT INTO mytable(user_id,thing_id,lock_date,lock_id)
VALUES
(51082,'299ac9ff-2b2b-102d-8ff6-f64c971398c3','2012-03-16 00:39:12','ec7b2008-6ede-11e1-aac2-5924aae99221'),
(108325,'299ac9ff-2b2b-102d-8ff6-f64c971398c3','2013-02-05 19:30:03','7c6de986-6edd-11e1-aac2-5924aae99221'),
(108325,'d90b354d-4b5f-11e0-9959-47117d41cf4b','2012-03-16 00:47:41','1c243032-6ee0-11e1-aac2-5924aae99221');
I want to delegate all records of user_id = 108325 to user_id = 51082, and if both users have an equal thing_id field, leave the newer one only (lock_date1 > lock_date2), so that I have following result:
51082,'299ac9ff-2b2b-102d-8ff6-f64c971398c3','2013-02-05 19:30:03','7c6de986-6edd-11e1-aac2-5924aae99221'
108325,'d90b354d-4b5f-11e0-9959-47117d41cf4b','2012-03-16 00:47:41','1c243032-6ee0-11e1-aac2-5924aae99221'
Note that 51082 now has a newer record: lock_date = '2013-02-05 19:30:03' instead of '2012-03-16 00:39:12'.
So, how can I update a row, and on duplicate key leave the newer one (by some particular field)?
Thanks!
INSERT INTO
mytable(user_id,thing_id,lock_date,lock_id)
VALUES
(51082,'299ac9ff-2b2b-102d-8ff6-f64c971398c3','2012-03-16 00:39:12','ec7b2008-6ede-11e1-aac2-5924aae99221'),
(108325,'299ac9ff-2b2b-102d-8ff6-f64c971398c3','2013-02-05 19:30:03','7c6de986-6edd-11e1-aac2-5924aae99221'),
(108325,'d90b354d-4b5f-11e0-9959-47117d41cf4b','2012-03-16 00:47:41','1c243032-6ee0-11e1-aac2-5924aae99221')
ON DUPLICATE KEY UPDATE SET
user_id = VALUES(user_id),
lock_date = VALUES(lock_date),
lock_id = VALUES(lock_id)

mysql trigger not working on insert

Table: items
Create Table:
CREATE TABLE `items` (
`ite_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`itemName` varchar(40) DEFAULT NULL,
`itemNumber` int(10) unsigned NOT NULL,
PRIMARY KEY (`ite_id`),
UNIQUE KEY `itemName` (`itemName`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
delimiter |
create trigger item_beforeinsert before insert on items
for each row begin
if new.itemNumber < 50 then
set new.ite_id = null;
end if;
end;
|
now the following command doesn't cause a trigger
insert items( itemname, itemnumber) values ( 'xyz', 1 );
any help would be very much appreciated, thanks!
Your ite_ID is not null and you want to set it null with your trigger, beside that it's auto increment, so you wont be able to 'control' all the values to assign to that field, I.E it wont overwrite values
It'd be
insert INTO items( itemname, itemnumber) values ( 'xyz', 1 );
also, since you have set ite_id as NOT NULL, you can't use a set new.ite_id = null;
For auto incremented primary key fields you can pass NULL value while inserting. MySQL automatically assigns auto generated value. It is not an error setting up NULL to it BEFORE insert. And hence trigger didn't fire an error.
Example:
insert into items( ite_id, ... ) values ( null, ... );
The above statement is valid and works, since ite_id field is primary key with auto increment.