Mysql insert multiple rows, if duplicate value column then update - mysql

I have a MySQL table that looks like this
id | customer_id | textkey | value |
---+-------------+---------+-------+
1 | 1 | text1 | value1|
2 | 1 | text2 | value2|
3 | 1 | text3 | value3|
4 | 1 | text4 | value4|
5 | 2 | text1 | value1|
...
I want to insert the following values to customer_id 1
(text1, valueX), (text3, valueY), (text5, value5), (text6, value6)
The end result should look like this
mysql> SELECT * from MyTable where customer_id=1;
id | customer_id | textkey | value |
---+-------------+---------+-------+
1 | 1 | text1 | valueX|
2 | 1 | text2 | value2|
3 | 1 | text3 | valueY|
4 | 1 | text4 | value4|
6 | 1 | text5 | value5|
7 | 1 | text6 | value6|
The value column should update whenever there is a duplicate in the textkey insert, and insert regularly if the textkey is not a duplicate. What query could I use to achieve this? I tried using IGNORE, LAST_INSERT_ID(), and ON DUPLICATE KEY UPDATE but I cant figure out what works for a "ON DUPLICATE COLUMN UPDATE" scenario. Thanks

You must create unique index which will detect the duplication:
CREATE UNIQUE INDEX idx ON test (customer_id, textkey);
Now you can use INSERT .. ODKU:
INSERT INTO test (customer_id, textkey, value) VALUES
(1, 'text1', 'valueX'),
(1, 'text3', 'valueY'),
(1, 'text5', 'value5'),
(1, 'text6', 'value6')
ON DUPLICATE KEY UPDATE
value = VALUES(value);
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=6dcc351706f574f4c9f13c1fc95b9225

Related

MySQL : How to filter query using "IN" on Composite Primary Key

I have a table in MySQL such the primary key is a composite one like this :
+--------------+----+------------------------------+
| fk_something | id | label |
+--------------+----+------------------------------+
| 1 | 1 | First record of something 1 |
| 2 | 1 | First record of something 2 |
| 2 | 2 | Second record of something 2 |
| 1 | 2 | Second record of something 1 |
| 2 | 3 | Third record of something 2 |
+--------------+----+------------------------------+
But now I have a tricky query to do, I want to retrieve for example the 2-1 and 1-2 records using a "IN" filter... How can I do it ?
I tried something like :
SELECT * FROM my_table WHERE id IN (1, 2) AND fk_something IN (2, 1)
But it gave me 1-1 and 2-2 records too ...
You can take advantage of the rarely used SQL feature called row value expressions:
SELECT * FROM myTable
WHERE (id, fk_something) IN (
(1, 2),
(2, 1),
(2, 3)
)

MySQL - multiple case when for varchars

I am trying to use CASE WHEN to count when specific text is withing the varchar column. I have been trying to crack it but I have an issue when second, third CASE WHEN is added.
The code I use and works is:
SELECT *,
CASE
WHEN (Orders.Some_text LIKE "%test%" AND Orders.Some_text NOT LIKE "%found%") THEN 1
ELSE 0 END AS Test
FROM Orders;
Now I add the second CASE WHEN:
SELECT *,
CASE
WHEN (Orders.Some_text LIKE "%test%" AND Orders.Some_text NOT LIKE "%found%") THEN 1
WHEN (Orders.Some_text LIKE "%test%" AND Orders.Some_text NOT LIKE "%missing%") THEN 1
ELSE 0 END AS Test
FROM Orders;
And it produces errors in the Test column.
Results I want are just simple 1 when word test is found and it is without found, missing or/and during.
+------+--------------+------------+
| id | Some_text | Test |
+------+--------------+------------+
| 1 | test | 1 |
| 2 | test found | 0 |
| 3 | found test | 0 |
| 4 | test missing | 0 |
| 5 | missing test | 0 |
| 6 | test during | 0 |
| 7 | during test found | 0 |
| 8 | abc | 0 |
+------+--------------+------------+
The code to reproduce my dataset:
CREATE TABLE Orders
(
id INT,
Some_text char(255));
insert into Orders values (1, "test");
insert into Orders values (2, "test found");
insert into Orders values (3, "found test");
insert into Orders values (4, "test missing");
insert into Orders values (5, "miss ing test");
insert into Orders values (6, "test during");
insert into Orders values (7, "during test found");
insert into Orders values (8, "abc");
It seems you need to check if both the words found and missing aren't there in the field, then set the value as 1.
Combine the statements like below and it should return expected output.
SELECT *,
CASE
WHEN (Orders.Some_text LIKE "%test%" AND
Orders.Some_text NOT LIKE "%found%" AND
Orders.Some_text NOT LIKE "%missing%") THEN 1
ELSE 0 END AS Test
FROM Orders;
Output
+------+--------------+------------+
| id | Some_text | Test |
+------+--------------+------------+
| 1 | test | 1 |
| 2 | test found | 0 |
| 3 | found test | 0 |
| 4 | test missing | 0 |
| 5 | missing test | 0 |
| 6 | test during | 1 |
| 7 | during test found | 0 |
| 8 | abc | 0 |

Insert If duplicate not found in table else update

I wanted to ignore or update duplicate when I am going to insert values. I know about on duplicate key but i can't figure out the solution with that. Here is sample table example.
| ID | roll | sub | mark |
| ---- |----------| ------|------|
| 1 | 100 | 11 | 15 |
| 2 | 101 | 11 | 16 |
| 3 | 102 | 11 | 17 |
| 4 | 100 | 12 | 10 |
| 5 | 101 | 12 | 11 |
| 6 | 102 | 12 | 12 |
Here the id is primary key but I wanted to insert to check if roll & sub already exist then update otherwise insert new row. I've tried with the following code but that's insert duplicate row but it should update row 6 in following table.
CREATE INDEX mycompo_index on student(roll,sub);
insert into student(roll, mark, sub)
values (102, 22, 12)
on duplicate key update mark = values(mark);
If the combination of roll and sub should be unique, you should define such a key in your table:
ALTER TABLE student ADD CONSTRAINT student_uq UNIQUE(roll, sub)
Note that if you do this, you don't have to explicitly create the index you're creating, the constraint will create on for you. Once you have this is place, you can use the on duplicate key syntax you were trying to use:
INSERT INTO student(roll, mark, sub)
VALUES (102, 22, 12)
ON DUPLICATE KEY UPDATE mark = VALUES(mark)

select from view -> update OR insert into table

I want to select data from a mysql-view which collects and joins data from "federated"-tables.
This data should be inserted into a table which looks very similar to the view.
an example would be:
table where data needs to be inserted or updated:
insertTable
+----+-----------+------+-------------+
| id | foreignId | data | foreignData |
+----+-----------+------+-------------+
| 1 | a | 111 | aaa |
| 2 | b | 222 | bbb |
+----+-----------+------+-------------+
the view where the data comes from:
dataView
+-----------+-------------+
| foreignId | foreignData |
+-----------+-------------+
| a | AAA |
| b | BBB |
| c | CCC |
+-----------+-------------+
insertTable
+----+-----------+------+-------------+
| id | foreignId | data | foreignData |
+----+-----------+------+-------------+
| 1 | a | 111 | AAA |
| 2 | b | 222 | BBB |
| 3 | b | | CCC |
+----+-----------+------+-------------+
and at this point i think i need a stored procedure which does following written in pseudo code
$result = SELECT * FROM dataView;
foreach $result as $row {
if(SELECT COUNT(*) FROM inserTable WHERE foreignId=$row[foreignId]>0)
UPDATE insertView SET foreignData = $row[foreignData] WHERE foreignId=$row[foreignId];
else
INSERT INTO insertView (id, foreignId, foreignData) VALUES (null,$row[foreignId],$row[foreignData];
}
You can use REPLACE query.
REPLACE INTO insertView (id, foreignId, foreignData) VALUES (null,$row[foreignId],$row[foreignData];
From mysql documentation
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. See
Section 13.2.5, “INSERT Syntax”.
PRIMARY KEY or a UNIQUE index not specified it will insert a new row.
So no need to SELECT checking.
The magic which is ideal for this problem was ON DUPLICATE KEY UPDATE
In my example the solution would look like this:
INSERT INTO insertTable
(
`foreignId`,
`foreignData`
)
SELECT
`dataView`.`foreignId`,
`dataView`.`foreignData`
FROM
`dataView`
ON DUPLICATE KEY UPDATE
`foreignId` = `dataView`.`foreignId`,
`foreignData` = `dataView`.`foreignData`;

Getting count of insert/update rows from ON DUPLICATE KEY UPDATE

I have a statement that tries to insert a record and if it already exists, it simply updates the record.
INSERT INTO temptable (col1,col2,col3)
VALUES (1,2,3)
ON DUPLICATE KEY UPDATE col1=VALUES(col1), col2=VALUES(col2), col3=VALUES(col3);
The full statement has multiple inserts and I'm looking to count number of INSERTs against the UPDATEs. Can I do this with MySQL variables, I've yet to find a way to do this after searching.
From Mysql Docs
In the case of "INSERT ... ON DUPLICATE KEY UPDATE" queries, the return value will be 1 if an insert was performed, or 2 for an update of an existing row.
Use mysql_affected_rows() after your query, if INSERT was performed it will give you 1 and if UPDATE was performed it will give you 2.
I've accomplished what you're describing using a while loop so that each iteration creates a MySQL statement that affects one row. Within the loop, I run the mysql_affected_rows() and then increment a counter depending upon whether the value returned was a 0 or a 1. At the end of the loop, I echo both variables for viewing.
The complete wording from MySQL Docs regarding the mysql_affected_rows function is (notice there are 3 possible values returned - 0, 1, or 2):
For INSERT ... ON DUPLICATE KEY UPDATE statements, the affected-rows
value per row is 1 if the row is inserted as a new row, 2 if an
existing row is updated, and 0 if an existing row is set to its
current values. If you specify the CLIENT_FOUND_ROWS flag, the
affected-rows value is 1 (not 0) if an existing row is set to its
current values.
(Sidenote - I set $countUpdate and $countInsert and $countUpdateNoChange to 0 prior to the while loop):
Here's the code that I developed that works great for me:
while (conditions...) {
$sql = "INSERT INTO test_table (control_number, name) VALUES ('123', 'Bob')
ON DUPLICATE KEY UPDATE name = 'Bob'";
mysql_query($sql) OR die('Error: '. mysql_error());
$recordModType = mysql_affected_rows();
if ($recordModType == 0) {
$countUpdateNoChange++;
}elseif($recordModType == 1){
$countInsert++;
}elseif($recordModType == 2){
$countUpdate++;
};
};
echo $countInsert." rows inserted<br>";
echo $countUpdateNoChange." rows updated but no data affected<br>";
echo $countUpdate." rows updated with new data<br><br>";
Hopefully, I haven't made any typos as I've recreated it to share while removing my confidential data.
Hope this helps someone. Good luck coding!
I know this is a bit old, but I was doing a bulk insert in PHP and needed to know exactly how many rows were inserted and updated (separately).
So I used this:
$dataCount = count($arrData); // number of rows in the statement
$affected = mysql_affected_rows(); // mysqli_*, PDO's rowCount() or anything
$updated = $affected - $dataCount;
$inserted = 2 * $dataCount - $affected;
Simple trace table:
-------------------------------
| data | affected | ins | upd |
-------------------------------
| 1 | 1 | 1 | 0 |
-------------------------------
| 2 | 2 | 2 | 0 |
| 2 | 3 | 1 | 1 |
| 2 | 4 | 0 | 2 |
-------------------------------
| 3 | 3 | 3 | 0 |
| 3 | 4 | 2 | 1 |
| 3 | 5 | 1 | 2 |
| 3 | 6 | 0 | 3 |
-------------------------------
| 4 | 4 | 4 | 0 |
| 4 | 5 | 3 | 1 |
| 4 | 6 | 2 | 2 |
| 4 | 7 | 1 | 3 |
| 4 | 8 | 0 | 4 |
-------------------------------
| 5 | 5 | 5 | 0 |
| 5 | 6 | 4 | 1 |
| 5 | 7 | 3 | 2 |
| 5 | 8 | 2 | 3 |
| 5 | 9 | 1 | 4 |
| 5 | 10 | 0 | 5 |
-------------------------------
if you want to get the number of records that have been inserted and updated separetly, you are to issue each statement separetly.