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

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

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.

Deleting Semi Duplicate Rows in ORACLE SQL

I have rows in my table that needs deleting based on a few columns being duplicates.
e.g Col1,Col2,Col3,Col4
If Col1,Col2 and Col3 are duplicates regardless of what value is in Col4 I want both these duplicates deleted. How do I do this?
You can do this using the where clause:
delete from t
where (col1, col2, col3) in (select col1, col2, col3
from t
group by col1, col2, col3
having count(*) > 1
);
Group by these IDs and check with HAVING whether there are duplicates. With the duplicates thus found delete the records.
delete from mytable
where (col1,col2,col3) in
(
select col1,col2,col3
from mytable
group by col1,col2,col3
having count(*) > 1
);
Use EXISTS to remove a row if another row with same col1, col2 and col3 exists with a lower col4 value. I.e keep one col1, col2, col3 row.
delete from tablename t1
where exists (select 1 from tablename t2
where t2.col1 = t1.col1
and t2.col2 = t1.col2
and t2.col3 = t1.col3
and t2.col4 < t1.col4)
To remove both/all rows, skip the col4 condition, do a group by instead:
delete from tablename t1
where exists (select 1 from tablename t2
where t2.col1 = t1.col1
and t2.col2 = t1.col2
and t2.col3 = t1.col3
group by t2.col1, t2.col2, t2.col3
having count(*) > 1)

Subquery for particular field value during INSERT from Table1 to Table2 in Oracle?

I'm attempting to create a short script which will take all of the fields from Table1 and insert them into Table2. The basic fields (col1, col2, col3, etc.) I have got covered by something like this:
INSERT INTO Table2 (col1, col2, col3, col4, col5, col6, col7)
SELECT col1, col2, col3, col4, col5, SYSDATE, USER
FROM Table1
I am having trouble though inserting the values for 2 fields in particular, col12/col13 of Table2. These columns are standalone in Table1, but in my new Table2 there the value referenced via foreign key ID to Table3/Table4. I'm now attempting to figure out how to do a proper subquery during my table INSERT from Table1 into Table2.
To try and better explain:
// Previously Used for DB
[Table1]
col12 -- CUSTOMER
col13 -- MERCHANT
//---------------
// NEW
[Table2]
col15 -- CUSTOMER_ID
col16 -- MERCHANT_ID
[Table3]
ID
CUSTOMER_DESC
CREATED_DATE
CREATED_BY
[Table4]
ID
MERCHANT_DESC
CREATED_DATE
CREATED_BY
Can anyone provide an example of the proper formatting for such a thing within my INSERT script? I'm envisioning it being something like:
INSERT INTO Table1 (col1, col2, col3, col4)
SELECT col1, col2, col3, [SELECT ID FROM Table3 WHERE Table3.CUSTOMER_DESC == Table2.CUSTOMER])
FROM Table2
My apologies if explanation isn't the clearest.
You need to properly JOIN to Table3, Table4 in order to get the referenced field values:
INSERT INTO Table2 (CUSTOMER_ID, MERCHANT_ID, col1, col2, etc...)
SELECT t3.ID, t4.ID, t1.col1, t2.col2, etc..
FROM Table1 t1
INNER JOIN Table3 t3 ON t1.CUSTOMER = t3.CUSTOMER_DESC
INNER JOIN Table4 t4 ON t1.MERCHANT = t4.MERCHANT_DESC
There should be no problem with the above query provided that there is a 1-1 relationship between Table1 and Table3 on fields CUSTOMER, CUSTOMER_DESC and Table1 and Table4 on fields MERCHANT, MERCHANT_DESC.
SQL Fiddle Demo
You almost got it right.
INSERT INTO Table1 (col1, col2, col3, col12)
SELECT col1, col2, col3, (SELECT customer_desc FROM Table3 WHERE Table3.ID = Table2.col15)
FROM Table2

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

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);