State Problem
Apart from 1st col in MySQL server which is PK and auto_increment, col "C" is STRING/VARCHAR. How do I use INSERT ... ON DUPLICATE KEY UPDATE on col "C".
Should I also set col "C" as UNIQUE as well?
Example
Assume that my table in MySQL server looks similar to this...
---------------------------
|ID(PK)| A | B | C | D | E |
+------+---+---+---+---+---+
| 1 | | | | | |
| 2 | | | | | |
| 3 | | | | | |
---------------------------
What I expect
The duplicate input must be ignored from the MySQL server.
Can I also send alert pop-up/session pop-up, if the duplicate has been inserted into MySQL server as "This query has already existed."?
Column C must be set to NOT NULL, UNIQUE then SQL will return error against attempt of duplicate value insert. You may handle that error in your backend code. Or you can handle and alter the duplicate value with 'ON DUPLICATE KEY UPDATE' clause:
INSERT INTO t1 (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
Related
I've created a new table like this:
+------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| first | varchar(100) | NO | PRI | NULL | |
| last | varchar(400) | NO | PRI | NULL | |
| source | varchar(100) | NO | | NULL | |
| count | int | YES | | 1 | |
+------------+--------------+------+-----+---------+-------+
And I try to insert multiple records to this table using this:
insert into my_table(first,last,source,count) values ('a','b','c',50),('a','b','c',20),('d','e','f',30) on duplicate key update count = count + 1;
After insert, this is the content of the table:
+------------+-----------+--------+-------+
| first | last | source | count |
+------------+-----------+--------+-------+
| a | b | c | 2 |
| d | e | f | 1 |
+------------+-----------+--------+-------+
However, I'd like the count to be updated by the numbers provided in the values of the new records (i.e., 50, 20, and 30 in the provided example). So, the table should look like this:
+------------+-----------+--------+-------+
| first | last | source | count |
+------------+-----------+--------+-------+
| a | b | c | 70 |
| d | e | f | 30 |
+------------+-----------+--------+-------+
Is it possible to achieve this using "on duplicate key update" in MySQL? Or is there any other efficient way to achieve this? The table will be very large (with millions of rows).
VALUES() is the method to use, as GMB mentioned, if you are on a mysql version older than 8.0.19. However, it was deprecated as of 8.0.20, if you are using mysql 8.0.19 or newer its recommended to give an alias to the rows being inserted, and then refer to the values of the inserts by the alias like this:
insert into my_table (first, last, source, count)
values ('a','b','c',50), ('a','b','c',20), ('d','e','f',30) as newRow
on duplicate key update count = count + newRow.count;
More information can be found here: https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
Consider the VALUES() syntax, that you can use in the on duplicate key clause to refer to the column value that would otherwise have been inserted:
insert into my_table(first, last, source, count)
values ('a','b','c',50), ('a','b','c',20), ('d','e','f',30)
on duplicate key update count = count + VALUES(count);
Note: first, last and source are MySQL keywords. I would not recommend using them as column names.
Suppose a table contains data like
MariaDB [c]> select * from t2;
+-----+
| abc |
+-----+
| 1 |
| 3 |
| 5 |
+-----+
Suppose my update command is
MariaDB [c]> update t2 set abc = abc+2;
It give following error
ERROR 1062 (23000): Duplicate entry '3' for key 'PRIMARY'
While the above command works fine in oracle 10g, Is it some kind of bug or what?
The following is just an illustration and trivial.
create table t2
( id int auto_increment primary key,
abc int not null,
unique key(abc)
);
insert t2(abc) values (1),(3),(5); -- 3 rows added
update t2 set abc = abc+2; -- Error Code 1062: Duplicate entry '3' for key 'abc'
The above error occurred because the update marched in the order of the primary key, also the physical ordering, and changing the 1 to a 3 violated the 3 that was already in place via the unique key. The fact that the end state would make every thing OK, ideally, doesn't keep it from failing at that moment.
To illustrate this working in this highly rigged example knowing there is no other data:
truncate table t2; -- the data wasn't modified but for the paranoid, clear and re-insert
insert t2(abc) values (1),(3),(5); -- 3 rows added
Try it bottom up (so that the Unique constraint is not violated):
update t2 set abc = abc+2 order by abc desc;
select * from t2;
+----+-----+
| id | abc |
+----+-----+
| 1 | 3 |
| 2 | 5 |
| 3 | 7 |
+----+-----+
It leverages the ability to have an order by in an update statement.
So it comes down to knowing your data and what you can get away with. Saying it worked on Oracle as you did in comments is on another db platform and with some other schema. So that is mute.
I've been trying to implement a simple script that locks a table from being read, updates some fields, and then unlocks it.
Here's my table:
mysql> SHOW COLUMNS FROM tb1;
+---------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------+------+-----+---------+-------+
| id | int(11) | YES | PRI | NULL | |
| status | int(1) | YES | | 0 | |
+---------------+---------+------+-----+---------+-------+
Lets see if you guys understand what I'm trying to do:
Start transaction
SELECT all rows with status != 1 (it may return more than 1 row) with FOR UPDATE statement;
UPDATE the field status of the rows that has been selected in pass 2
Commit
I tried to achieve this in many ways, but I cant persist the SELECT data that I got in pass 2 and I can't use SELECT ... FOR UPDATE as a subquery of a UPDATE like this UPDATE tb1 SET status=1 WHERE id IN (SELECT id FROM tb1 WHERE status != 1 FOR UPDATE);
Is it possible to achieve this instead of updating row by row?
I'm trying like hours to make a simple MySQL command and it won't work.
I have a database where package IDs for Apps are stored, like 'com.android.package'.
They are stored like so:
| ID | PackageID | PackageDesc |
| 1 | com.android.package | This is a package |
| 2 | com.android.test2pa | This is package 2 |
And so on...
Now I want to insert a new entry, if 'com.android.package' don't exist and if it exists, I want to do nothing...
I've tried following:
INSERT INTO Packages (PackageID) VALUES ('com.android.package') ON DUPLICATE KEY UPDATE PackageID=VALUES(PackageID)
But it still creates new entries, like that:
| ID | PackageID | PackageDesc |
| 3 | com.android.package | |
| 4 | com.android.package | |
| 5 | com.android.package | |
I don't know where's my error.
A proposed Packages table schema for ON DUPLICATE KEY UPDATE to work as expected is the following:
CREATE TABLE Packages (
`ID` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`PackageID` VARCHAR(30) NOT NULL,
`PackageDesc` VARCHAR (100),
UNIQUE(`PackageID`)
);
After this statement is executed:
INSERT INTO Packages (PackageID, PackageDesc) VALUES
('com.android.package', 'This is a package')
ON DUPLICATE KEY UPDATE PackageID=VALUES(PackageID);
Packages contains the following row:
# ID, PackageID, PackageDesc
'1', 'com.android.package', 'This is a package'
If you now execute the following statement:
INSERT INTO Packages (PackageID, PackageDesc) VALUES
('com.android.package', 'This is a package2')
ON DUPLICATE KEY UPDATE PackageID=VALUES(PackageID), PackageDesc=VALUES(PackageDesc);
Packages contains:
# ID, PackageID, PackageDesc
'1', 'com.android.package', 'This is a package2'
This means an UPDATE was performed by the latter INSERT INTO.
Demo here
I want to be able to insert data into t1 and have data get populated in table t2 with the primary key as a foreign key in t2.
Basically, how come in my current setup when I INSERT INTO t1 (first_name, last_name) values ( "blah", "blah"); and then do SELECT * FROM t2; t2 it says Empty Set (0.00 sec) for t2? Shouldn't it at least show the default id of 1?
t1:
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| first_name | varchar(20) | NO | | NULL | |
| last_name | varchar(20) | NO | | NULL | |
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
+------------+------------------+------+-----+---------+----------------+
t2:
+-----------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+-------+
| address | varchar(50) | NO | | NULL | |
| id | int(10) unsigned | NO | MUL | NULL | |
| last_name | varchar(20) | YES | | NULL | |
+-----------+------------------+------+-----+---------+-------+
In a relational database, a FOREIGN KEY is a declaration that you intend to insert values into T2 that must match an already existing value in T1, and that you want the database to refuse to perform any action that would break this relationship.
It does not mean that the database will create records on its own in order to satisfy a relationship. If you try to insert a value into T2 that does not exist in T1, the command will fail; it will not add the required record to T1.
That is the opposite of what you're suggesting, however, in which you want the foreign key values to get automatically generated. However, there's no requirement that a primary key value actually have references and, furthermore, no limit on the number of times that primary key value can be referenced — so how would the database guess what should be created in T2?
That said, if you want some of your own code to execute automatically when data is added to T1, code which can do whatever you want, you can create a trigger on T1.
No, tables won't propagate automatically. (You can however do it with triggers) You will have to insert into t2.
You can create a trigger on table t1 so that it inserts a row into t2 with the correct id and the other fields NULL
Foreign keys will not insert records for you.
DELIMITER ;;
CREATE TRIGGER insert_addr_rec BEFORE INSERT ON t1
FOR EACH ROW BEGIN
INSERT INTO t2 SET id=NEW.id, last_name=NEW.last_name
END ;;
DELIMITER ;
NB untested code