I have a table with these columns: Player_name | Item_name | Amount
I do not know how to perform this conditional INSERT:
INSERT INTO Needed_items(Player_name,Item_name) VALUES('foo','foo');
if Player_name and Item_name already exist, so if a Player already owns a given item, I need to increment Amount field, else I need to insert a new row into the table.
Thanks for the help
Try something like this:
INSERT INTO Needed_items(Player_name,Item_name) VALUES('foo','foo')
ON DUPLICATE KEY UPDATE Amount=Amount+1
Related
I have a users table as below:
id --- name --- email --- gender
id column is both primary key and unique key. Here I'd like to update the rows with new name and email information but I don't have to change their gender. I tried to update table using query:
INSERT INTO USERS VALUES(id, name, email) ON DUPLICATE KEY UPDATE name=VALUES(name), email=VALUES(email);
It did not work and alerted as:
Column count doesn't match value count at row 1
For example, assume we have one row as follows:
id=1 | name='Mike' | email='mike#mike.com' | gender='male'
How to use on-duplicate-key update to change name to 'Michael'?
id=1 | name='Michael' | email='mike#mike.com' | gender='male'
Thanks.
[UPDATE: adapted to question update]
Your problem is in the insert field already, you give only three values. For that you need
INSERT INTO users (id, name, email)
VALUES (42, "patrick","patrick#home")
ON DUPLICATE KEY UPDATE name="patrick", email="patrick#home";
But still think twice if your program really does what you want, especially if it is possible that two incoming requests get the same new id.
I have the following table in mariadb:
-id = key which shall autoincrement
-price
-amount
-name
-order_id
order_id can appear twice in the table but the combination of name and order_id should be unique. I now have a combination of name and order_id.
What I want to do is to add a record if the combination of name and order_id is not in the table.
If it's in then I want to change/get the amount value.
Is there a nice query to accomplish this?
Regards
I like using on duplicate key update for this. You need to start by creating a unique index on name and order_id:
create unique index ix_table_orderid_name on table(order_id, name);
Then the insert looks like:
insert into table(price, amount, name, order_id)
values (#price, #amount, #name, #order_id)
on duplicate key update amount = values(amount), price = values(price);
This replaces the values in the table with the new values. You can also increment them. Your question is unclear on the exact operation.
Consider following tables:
product
+----+------+-------------+
| id | name | category_id |
+----+------+-------------+
| 1 | foo | 1 |
+----+------+-------------+
categories
+----+------+
| id | name |
+----+------+
| 1 | food |
+----+------+
Now lets assume I someone POSTs a new product:
{
"name": "bar",
"category": "drink"
}
In this case we need to create the new category automatically:
INSERT IGNORE INTO categories (name) VALUES ('drink')
Then we finally could insert the actual product row:
INSERT INTO products (name, category_id) VALUES ('bar', SELECT id FROM categories WHERE name = 'drink')
However though this works it would require a transaction setup to be safe and as this does not seem to be a super complicated query I would like to know if it would be possible to merge both queries together (e.g. put the insert query of the categories into the select subquery of the product insertion)?
I would advise against INSERT IGNORE, for the reasons that #Bill Karwin so eloquently explains. Furthermore, as documented under INSERT ... ON DUPLICATE KEY UPDATE Syntax:
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;
One can then obtain the id (whether preexisting or newly inserted) as documented under How to Get the Unique ID for the Last Inserted Row:
If you insert a record into a table that contains an AUTO_INCREMENT column, you can obtain the value stored into that column by calling the mysql_insert_id() function.
[ deletia ]
When a new AUTO_INCREMENT value has been generated, you can also obtain it by executing a SELECT LAST_INSERT_ID() statement with mysql_query() and retrieving the value from the result set returned by the statement.
So, for example, one could simply do:
INSERT INTO categories (name) VALUES ('drink')
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id);
INSERT INTO products (name, category_id) VALUES ('bar', LAST_INSERT_ID());
Of course, these statements would still need to be executed within a transaction if you require atomicity.
No, that is not possible. What you can do however, is creating a BEFORE INSERT trigger on the product table and check inside the trigger, if the category already exists. In case it doesn't exist, you can create it there.
The trigger will be automatically executed in the same transaction as your INSERT-statement, so no additional transactions necessary there.
The only problem I see is, when you forget about the Trigger, you might start wondering why categories appear automatically for each new product with a new category (something similar happened to me).
Update:
You can see example of simple triggers in the MySQL Documentation
You can access the new to be inserted value in a BEFORE INSERT trigger with NEW.column_name so for you it would be NEW.category
I simply want to replace (update) DATE, PRICE and OLDPRICE when a price is different than the PRICE in my table where MODEL is unique.
Sample Row Table Data:
DATE | MAKE | MODEL | PRICE | OLDPRICE
2012-04-15 | Advance | DTA-100-X | 400 | 390
There must be a dozen ways to do this but I'm looking for the best solution to use in a MySQL query.
Should I be using:
INSERT INTO..ON DUPLICATE KEY UPDATE
REPLACE INTO..
UPDATE...WHERE PRICE != XXX
Essential syntax would be to UPDATE if the MODEL is the same but the PRICE is different; OLDPRICE becomes PRICE on UPDATE
*UPDATE*
This REPLACES whether price changed or not. I only want updates/replaces if price changed ie, this should NOT update anything given above example, however it does because date is different:
REPLACE INTO MyTable (DATE, MAKE, MODEL, PRICE, OLDPRICE) VALUES ('2012-10-02', 'Advance', 'DTA-100-X', '400', '390')
MySQL has a REPLACE statement specifically for this purpose.
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
-- http://dev.mysql.com/doc/refman/5.6/en/replace.html
If you care about the order of the table, use INSERT INTO..ON DUPLICATE KEY UPDATE. REPLACE will delete the old row and then add a new one, if it finds a duplicate.
INSERT INTO..ON DUPLICATE KEY UPDATE does, as the name suggests, inserts a new row into the table unless there's a duplicate, in which case it will update the row (instead of removing it and adding a new one) which will make the order of the table the same.
Based on your update, you should use option 1, the upsert, aka INSERT...ON DULICATE KEY UPDATE.
I think you are saying you only want to update the PRICE and OLDPRICE (not DATE or MAKE) if the model already exists with a difference price. If that's the case, this should work for you:
Like this:
INSERT INTO MyTable (DATE, MAKE, MODEL, PRICE, OLDPRICE)
VALUES ('2012-10-02', 'Advance', 'DTA-100-X', '410', '390')
ON DUPLICATE KEY UPDATE OLDPRICE = CASE WHEN PRICE != VALUES(PRICE) THEN PRICE ELSE OLDPRICE END,
DATE = CASE WHEN PRICE != VALUES(PRICE) THEN VALUES(DATE) ELSE DATE END,
PRICE = VALUES(PRICE);
I have a table which contains the items the users of my game owns. If a user buys a new item, it should be inserted, but if he already got it, it should be increased instead.
I understand I can use INSERT ... ON DUPLICATE KEY UPDATE, but I don't understand how in my problem.
The item_id isn't unique, because many players can own the same weapon (ie. a longsword). The user_id isn't unique either, because a player can own many items.
So, my question is how to make the query UPDATE instead of INSERT if a row containing both the user_id and item_id already exists?
I know this question is old but none of the answers are correct.
You need a PRIMARY or UNIQUE index on user_id and item_id (both columns in one index).
Then you can use "INSERT INTO ... VALUES ... ON DUPLICATE KEY UPDATE count=count+1" no problem.
This is EXACTLY what ON DUPLICATE UPDATE will do for you.
That's not what the "ON DUPLICATE KEY UPDATE" will do for you. If it were me, I would attempt the insert. If it failed, check why (you're checking for errors already, right?). If it's because of a duplicate key, do your update. If the error is for some other reason, then handle that appropriately.
You do want ON DUPLICATE KEY UPDATE. It looks for the Primary Key of the table, and if it exists, updates all the other rows.
So your table has a primary key of (userid, itemid) and the following values:
userid itemid strength
4 5 6
And you want to bump it to strength=9, use this:
INSERT INTO table ON DUPLICATE KEY UPDATE VALUES(4,5,9)
It will insert a row with 4,5,9 if it doesn't exist, and will update strength to 9 on the row with primary key (4,5) if it does exist. It won't update any other rows (e.g. rows with userid4 but itemid 10 or itemid 5 but userid 70) because they don't match the whole PK.
You could do something like the following (assumes your user id is in the variable UserID and item ID is in item_ID) :
SELECT
#rowCount := COUNT(*)
FROM
table
WHERE
user_id = UserID
AND item_id = ItemID;
IF (#rowCount > 0) THEN
... do update
ELSE
... do insert
END IF;
Can you do something like
UPDATE TABLE
set COL = 'BLAH BLAH'
where ITEM_ID = #itemid AND USER_ID = #userid
IF ##ROWCOUNT = 0
BEGIN
INSERT INTO TABLE (col...)
VALUES (vals...
END