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
Related
Let's suppose I have the following table in a MySQL DB
Table: Debt
ID | Customer | Amount
---------------------
1 | Peter | $ 80
2 | John | $120
What I want to do is sum a new amount of money to the already pending one for a given customer. What I've been doing so far is a SELECT to check if the customer exist in the table. If it does then I UPDATE the register with the sum of the previous value plus the new one. If the register doesn't exist the I proceed to INSERT.
As you can see I'm using two operations, a SELECT and an UPDATE, or a SELECT and and INSERT.
My question is if there is a way to do this with only one single operation
https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
Set amount = amount + ?? in the on duplicate update clause.
MySql does allow to update an existing record or insert one, use INSERT INTO table (id, name, amount) VALUES (1, 'Peter', 80) ON DUPLICATE KEY UPDATE;
I don't know though if you could use the existing value to do a sum with the new and insert the result.
Probably you'd need triggers for that...
I have a table that contains
id | user | date | data1 | data2 ......
where id is the primary unique key.
I'm trying to write a query that can UPDATE if both user and date exist while INSERT if either one of them doesn't exist
I thought about the INSERT INTO...ON DUPLICATE KEY...UPDATE method, but that requires using the unique key, which I do have but not using.
What would be a good way to deal with this issue?
Per discussion in comments, you should make (user, date) a unique key.
This will trigger the INSERT INTO ... ON DUPLICATE KEY UPDATE query as expected, updating rows with matching user and date fields, and inserting new ones where no match is found.
The only valid option is to implement this UPSERT in the programming language that you use with mysql, because MySQL needs a unique key for both INSERT ... INTO and REPLACE.
Or to add a unique index on the user and date columns which seems to be in concordance with your business logic anyway.
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 am a newbie to mysql. Please help.
I have a table people like this. The only primary key of people is id
id name age sex
1. John 16 M
2. Peter 18 K
I would like to write some sql to insert some rows to people. But if the name is already exist
in the table. I do not insert new row. For example, if I insert the row with the name John and
Peter. I do not insert rows.
I have a variable name as var_name;
I have search out for the web for a very long time.
I use the following sql recommend by the web
INSERT into People(name) values(var_name) where not exists(SELECT name from People
where name = var_name)
But the sql syntax error comes out. Why would this happen. And is there any fast way to acheieve my goal.
The best way to do this is to create a unique index on name:
create unique idx_people_name on people(name)
Then, when you insert, use on duplicate key update:
INSERT into People(name)
values(var_name)
on duplicate key update name = values(name);
The update piece does nothing -- it is a "no-op". But this puts the logic in the database and enforces that names need to be unique.
For your query to work, you need insert . . . select. The values clause doesn't take a where statement:
INSERT into People(name)
select var_name
from dual
where not exists(SELECT name from People where name = var_name);
If you have a unique constraint on the name, I believe you can use:
INSERT IGNORE People(name) VALUES (var_name);
I have a lookup table that has 3 rows:
id | name
=== =======
1 Pendig
2 Sent
3 Failed
When I insert this data into the another table on another server/database, how can I ensure the same values (names) are created with the same auto-incrementing ids?
Since it is a lookup table, can I just insert into the table and specify the id?
You can always overwrite the insert ID in an auto_increment table by specifying it:
INSERT INTO yourtable (id, name) VALUES (2, 'Sent');
and 2 will be stuff into the table as the ID value. This works perfectly until any OTHER inserts are performed and the table's built-in auto_increment value happens to come up to a value that you yourself inserted, e.g, assuming a brand new freshly created table:
INSERT INTO yourtable (id, name) VALUES (2, 'Sent'); // force an ID
INSERT INTO yourtable (id, name) VALUES (NULL, 'foo'); // DB assigns 1
INSERT INTO yourtable (name) VALUES ('foo'); // DB assigns 2
The first query succeeds, the second query succeeds, the third query fails with a primary key violation, because the DB-generated '2' id now conflicts with the one you inserted manually.
If you want to ensure ID and auto_increment compatibility between different DB instances, then use mysql_dump to spit out the table for you. It'll ensure that all the IDs in the table are preserved, and that the internal auto_increment pointer is also sent across properly.
Since you have the lookup table to begin with it should be irrelevant what the id actually is. That is to say that you should never look at the id itself and only use it for joins and the like. If you want to look up this transparent id, you should use the name.
To answer your specific question, yes you can specify auto increment IDs during inserts:
INSERT INTO t1 (id, name) VALUES (1, 'Pendig')