Ways to update a dependent table in the same MySQL transaction? - sql

I need to update two tables inside a single transaction. The individual queries look something like this:
1. INSERT INTO t1 (col1, col2)
VALUES (val1, val2)
ON DUPLICATE KEY
UPDATE col2 = val2;
If the above query causes an insert then I need to run the following statement on the second table:
2. INSERT INTO t2 (col1, col2)
VALUES (val1, val2)
ON DUPLICATE KEY
UPDATE col2 = col2 + val2;
otherwise,
3. UPDATE t2
SET col2 = col2 - old_val2 + val2
WHERE col1 = val1;
-- old_val2 is the value of
t1.col2 before it was updated
Right now I run a SELECT on t1 first, to determine whether statement 1 will cause an insert or update on t1. Then I run statement 1 and either of 2 and 3 inside a transaction. What are the ways in which I can do all of these inside one transaction itself?
The approach I was thinking of is the following:
UPDATE t2, t1
set t2.col2 = t2.col2 - t1.col2
WHERE t1.col1 = t2.col2
and t1.col1 = val1;
INSERT INTO t1 (col1, col2)
VALUES (val1, val2)
ON DUPLICATE KEY
UPDATE col2 = val2;
INSERT INTO t2, t1 (t2.col1, t2.col2)
VALUES (t1.col1, t1.col2)
ON DUPLICATE KEY
UPDATE t2.col2 = t2.col2 + t1.col2
WHERE t1.col1 = t2.col2
and t1.col1 = val1;
Unfortunately, there's no multi-table INSERT... ON DUPLICATE KEY UPDATE in MySQL 5.0. What else could I do?

If you execute an INSERT or an UPDATE, your client is able to fetch the number of rows that changed. How to do this depends on your client, but for several programming languages, this number is returned by your INSERT if it was successful.
If you execute INSERT...ON DUPLICATE KEY UPDATE, you can as well fetch this number, but it is not exactly what you expect it to be. If you insert/update a single row, you receive 1 as the number of rows that changed in case of an INSERT and 2 in case of an UPDATE, even though there is only one row that changed. You could use this number to decide on the client side which query to run next.
Not as nice as a single transaction, but at least you get rid of one SELECT.

Okay, so I've got this figured out and done in a way that I like it:
UPDATE t2, t1
SET t2.col2 = t2.col2 - t1.col2
WHERE t1.col1 = t2.col2
AND t1.col1 = val1;
INSERT INTO t1 (col1, col2) VALUES (val1, val2)
ON DUPLICATE KEY UPDATE
col2 = val2;
INSERT INTO t2 (col1, col2) VALUES (val1, val2)
ON DUPLICATE KEY UPDATE
col2 = col2 + VALUES(col2);
The third query can be rewritten to refer to values from t1 like such:
INSERT INTO t2 (col1, col2)
SELECT col1, col2 FROM t1 WHERE col1 = val1
ON DUPLICATE KEY UPDATE
t2.col2 = t2.col2 + VALUES(col2);

Related

Add two values from one table then insert into a new column on another table

The goal is to add two values from an existing table, then have the sum value replace the value from the existing table to make the new file my boss wants.
All while keeping the data from the existing table as is...only updating the new one.
After looking around online I started working on an insert statement like the one below:
insert into temptable1 (col1, col2,col3, col4,col5,col6,col7,col8)
select col1, col2, max(col3), max(col4),max(col5),max(col6),max(col7),max(col8)
from temptable2
group by col1, col2
then tried updating the table with the sums:
Update t1
Set t1.col8 = t2.col8
FROM temptable1 t1
INNER JOIN (select col1, col2, sum(col6 + col7) as col8
from temptable2 group by col1, col2) as t2
on t2.col1 = t1.col1
Update t1
Set t1.col5 = t2.col5
FROM temptable1 t1
INNER JOIN (select col1, col2, sum(col3 + col4) as col5
from temptable2 group by col1, col2) as t2
on t2.col1 = t1.col1
Afterwards it goes into another insert statement that talks to the related perma tables in the database. I can execute this without getting any errors but the report I'm getting as a result of this script doesn't look unchanged in the slightest.
temtable2 in this example is the one that would have existing data, temptable1 is the one that should have the summations.

Insert into one table from another Postgres based on two columns

I have two tables with the same columns, There are no unique columns for these tables. Lets say the columns are Col1, Col2, Col3 and Col4. The tables are T1 and T2.
What I want to do is insert all the rows from T2 to T1 where Col1 & Col2 combinations do not exist in T1 already. Col1 is a string and Col2 is an int.
So for example Col1 = "APPLE" and Col2 = "2019". If a row contains Col1 = "APPLE" and Col2=2019 in T2 I do not want to insert it into T1 whereas if a row contains Col1 = "APPLE" and Col2=2020 then I want to insert it into T1.
I am trying to find the easiest solution to do this and cant seem to find a straightforward way using INSERT INTO WHERE NOT EXISTS or using UPSERT.
You can use insert ... select ... where not exists with tuple equality to compare (col1, col2):
insert into t1(col1, col2, col3, col4)
select * from t2
where not exists (
select 1 from t1 where (t1.col1, t1.col2) = (t2.col1, t2.col2)
)
With NOT EXISTS:
insert into t1(Col1, Col2, Col3, Col4)
select Col1, Col2, Col3, Col4
from t2
where not exists (
select 1 from t1
where t1.Col1 = t2.Col1 and t1.Col2 = t2.Col2
)
See a simplified demo.

Get all permutations of values - into pairs

I have X amount of values being passed into a table via CSV - so I take 99315,99316,99223 and split them out into a single column temp table - each value in the CSV into a single row.
What I need to be able to do is to get every permutation of values in pairs -
so - something like:
Col1 Col2
99315 99316
99315 99223
99316 99315
99316 99223
99223 99315
99223 99316
select t1.col1, t2.col1 col2
from mytable t1
cross join mytable t2
if you want to exclude like values add
where t1.col1 <> t2.col1
A faster way to write this query is to just do
SELECT t1.col1, t2.col1 col2
FROM table1 t1, table2 t2
and then you can add filters with a WHERE as well

Updating more than 1 db column in an UPDATE SET statement using psycopg2

I try to update one table based on values found in another table. The following works:
UPDATE table1 SET col1 = ( SELECT col1 from table2 WHERE table2.col1 = table1.col1 );
I want to do the same using several columns. I thought the following should bring the desired result"
UPDATE table1 SET (col1, col2) = ( SELECT col1, col2 from table2 WHERE table2.col1 = table1.col1 );
but I get a
syntax error at or near "SELECT"
LINE 1: UPDATE table1 SET (col1, col2) = ( SELECT col1, col2 f...
Any help appreciated.
This should work:
update table1 t1
set col1 = t2.col1,
col2 = t2.col2
from table2 t2
where t1.col1 = t2.col1;
SQL Fiddle Demo
With that said, no need to update col1 = t2.col1 since that is your join criteria.

How to determine table row causing duplicate entry error in INSERT?

As I get a lot of answers trying to help me with getting around the error:
I am mostly interested in a way to do error handling and to detect the table row creating an error than getting around my actual problem which I only use to illustrate what is coded in the stored procedure.
I am doing an SQL Insert statement in a stored procedure for entries missing in the table:
INSERT INTO dbo.t1
(col1, col2, col3, col4, col5)
SELECT DISTINCT col1, col2, col3, col4, col5
FROM dbo.t2
WHERE (NOT EXISTS
(SELECT col1, col2, col3, col4, col5
FROM t1 AS Table_1
WHERE (col1 = t2.col1) AND
(col2 = t2.col2) AND
(col3 = t2.col3) AND
(col4 = t2.col4) AND
(col5 = t2.col5))) AND
col2 = 'VALUE'
t1.col1 + t1.col2 and t1.col3 + t1.col4 have a foreign key relation to another table t3.col1 + t3.col2
The stored procedure fails to finish throwing an error message that the foreign key relation has been violated; i.e. there are some entries missing in t3:
Msg 547, Level 16, State 0 [...] INSERT statement is in conflict with
FOREIGN-KEY [..]
What I would like to know is the TABLE ROW of t2 causing the error, optimally the values in this row. I googled quite a lot about SQL error handling, but only found examples providing the coding line raising the error - which is useless information for me...
Any help appreciated
The error is pretty clear, it seams like you are trying to insert a value in the column with the FK constraint that is not found in the primary key column of the referenced table.
From the query you posted, you are trying to insert all values from dbo.t2 that doesn't exist in the first table. Then you can use EXCEPT operator to insert only the values of col1, col2, col3, col4, col5 that found in the dbo.t2 that doesn't present in dbo.t1 something like:
INSERT INTO dbo.t1
(col1, col2, col3, col4, col5)
SELECT * FROM
(
SELECT col1, col2, col3, col4, col5
FROM dbo.t2
EXCEPT
col1, col2, col3, col4, col5
FROM dbo.t1
)
This way you will guarantee that only the rows that doesn't present in dbo.t1 get inserted.
If you want to get the data that cause the duplicate entry you can use the INTERSECT to get them.
INSERT INTO dbo.t1(col1, col2, col3, col4, col5)
SELECT DISTINCT col1, col2, col3, col4, col5
FROM dbo.t2 left join dbo.t1
on t2.col1=t1.col1 and
t2.col2=t1.col2 and
t2.col3=t1.col3 and
t2.col4=t1.col4 and
t2.col5=t1.col5
where t1.col1 is null and t1.col2 is null and t1.col3 is null and t1.col4 is null and t1.col5 is null
I think it is possible, that in t2 you have rows with values which are not exists in t3. (That's why the reference is violated.)
Make sure that t2 has only the values which are exists in t3.
You can try using INNER JOINs on your data to remove violating rows.
Try this using NOT IN
INSERT INTO TABLE_2
(id, name) SELECT t1.id, t1.name
FROM TABLE_1 t1 WHERE t1.id NOT IN (SELECT id FROM TABLE_2)
SELECT column1, column2, column3
FROM Table2 T2
LEFT JOIN Table1 T1 ON T1.col1 = T2.column1 and T1.col2 = T2.column2 and T1.col3=T2.column3
WHERE T1.col1 IS NULL and T1.col2 IS NULL and T1.col3 IS NULL