Update fails with duplicate row - sql

I am teaching myself SQL with a small database I inherited. While I was playing with Update(),
update a
from sls_ord_fact a, sls_ord_dim b
set cust_acct_key = b.cust_acct_key
where a.sls_ord_key = b.sls_ord_key
and a.sls_ord_key <> 0
and b.cust_acct_key <> 0
and a.cust_acct_key <> b.cust_acct_key;
I triggered this error :Duplicate row error in SLS_ORD_FACT
How can identify the duplicate record??? I don't know the data very well.....

It looks like you're trying to set the primary key of the SLS_ORD_FACT table (presumably that is cust_acct_key), and the new value you're trying to set it to already exists in the table. Since primary keys must be unique, this causes an error. The duplicate key is in b - in fact, it's b.cust_acct_key, which is probably a foreign key to SLS_ORD_FACT.cust_acct_key.

Related

A query to update group of related items with their main primary key (parent keys)

I Need to update the TS_PARENT_TS_ID column with the TS_ID column(Primary Key). Using the first rowas example, see column name (TS_TERM_TYPE_NAME), You have "MAIN" directly under it is "RELATED(s)". all of which are related to each other, hence should have the same foreign keys in column (TS_PARENT_TS_ID)and in this case 1235. Another way to think about this is, in TS_TERM_TYPE_NAME column ALL "MAIN" that are followed with "RELATED(s)" belong to the same family and hence, should have the same (TS_PARENT_TS_ID). Can you help with a query that would update all Column (TS_PARENT_TS_ID) "RELATED" with (TS_PARENT_TS_ID) of "MAIN".
Thank you!
If these are related through the last column -- which seems likely -- then:
update t
set ts_parent_id = (select max(t2.ts_parent_id)
from t t2
where t2.ts_term_type = 'MAIN' and
t2.ts_notation = t.ts_notation
)
where ts_term_type = 'RELATED';

SQL/DB2 SQLSTATE=23505 error when executing an UPDATE statement

I am getting a SQLSTATE=23505 error when I execute the following DB2 statement:
update SEOURLKEYWORD
set URLKEYWORD = REPLACE(URLKEYWORD, '/', '-')
where STOREENT_ID = 10701
and URLKEYWORD like '%/%';
After a quick search, a SQL state 23505 error is defined as follows:
AN INSERTED OR UPDATED VALUE IS INVALID BECAUSE THE INDEX IN INDEX SPACE CONSTRAINS COLUMNS OF THE TABLE SO NO TWO ROWS CAN CONTAIN DUPLICATE VALUES IN THOSE COLUMNS RID OF EXISTING ROW IS X
The full error I am seeing is:
The full error I am seeing is:
DB2 Database Error: ERROR [23505] [IBM][DB2/LINUXX8664] SQL0803N One or more values in the INSERT statement, UPDATE statement, or foreign key update caused by a DELETE statement are not valid because the primary key, unique constraint or unique index identified by "2" constrains table "WSCOMUSR.SEOURLKEYWORD" from having duplicate values for the index key. SQLSTATE=23505
1 0
I'm not sure what the "index identified by '2'" means, but it could be significant.
The properties of the columns for the SEOURLKEYWORD table are as follows:
Based on my understanding of this information, the only column that is forced to be unique is SEOURLKEYWORD_ID, the primary key column. This makes it sound like the update statement I'm trying to run is attempting to insert a row that has a SEOURLKEYWORD_ID that already exists in the table.
If I run a select * statement on the rows I'm trying to update, here's what I get:
select * from SEOURLKEYWORD
where storeent_id = 10701
and lower(URLKEYWORD) like '%/%';
I don't understand how executing the UPDATE statement is resulting in an error here. There are only 4 rows this statement should even be looking at, and I'm not manually updating the primary key at all. It kind of seems like it's reinserting a duplicate row with the updated column value before deleting the existing row.
Why am I seeing this error when I try to update the URLKEYWORD column of these four rows? How can I resolve this issue?
IMPORTANT: As I wrote this question, I have narrowed down the problem to the last of the four rows in the table above, SEOURLKEYWORD_ID = 3074457345616973668. I can update the other three rows just fine, but the 4th row is causing the error, I have no idea why. If I run a select * from SEOURLKEYWORD where SEOURLKEYWORD_ID = 3074457345616973668;, I see only the 1 row.
The error is pretty clear. You have a unique index/constraint in the table. Say you have two rows like this:
STOREENT_ID
URLKEYWORD
10701
A/B
10701
A-B
When the first version is replaced by 'A-B', the result would violate a unique constraint on (STOREENT_ID, URLKEYWORD) or (URLKEYWORD) (do note that other columns could possibly be included in the unique constraint/index as well).
You could avoid these situations by not updating them. I don't know what columns the unique constraint is on, but let's say only on URLKEYWORD. Then:
update SEOURLKEYWORD
set URLKEYWORD = REPLACE(URLKEYWORD, '/', '-')
where STOREENT_ID = 10701 and
URLKEYWORD like '%/%' and
not exists (select 1 from SEOURLKEYWORD s2 where replace(s2.urlkeyword, '/', '-') = REPLACE(SEOURLKEYWORD.URLKEYWORD, '/', '-')
);
Note the replace() is required for both columns because you might have:
A-B/C
A/B-C
These only conflict after the replacement in both values.
To complement the answer given by #GordonLinoff, here is a query that can be used to find a table's unique constraints, with their IDs, and the columns included in them:
SELECT c.tabschema, c.tabname, i.iid AS index_id, i.indname, ck.colname
FROM syscat.tabconst c
INNER JOIN syscat.indexes i
ON i.indname = c.constname -- unique index name matches constraint name
AND i.tabschema = c.tabschema AND i.tabname = c.tabname
INNER JOIN syscat.keycoluse ck
ON ck.constname = c.constname
AND ck.tabschema = c.tabschema c.tabname = ck.tabname AND
WHERE c.type = 'U' -- constraint type: unique
AND (c.tabschema, c.tabname) = ('YOURSCHEMA', 'YOURTABLE') -- replace schema/table
ORDER BY i.iid, ck.colseq

Primary key violation while merging data from another table

I have two tables, TBTC03 and TBTC03Y, with TBTC03Y having two extra columns as EFFDTE and EXPDTE. I have to merge the data from TBTC03 to TBTC03Y with the following logic:
If no matching TC03 entry is found in TC03Y
a new TC03Y record is build with the TC03 data
the Effective Date will default to '01-01-1980'
the Expiration Date will default to '09-30-1995'
I wrote a query for the same as :
insert into TBTC03Y (LOB,MAJPERIL,LOSSCAUSE,NUMERICCL,EFFDTE,EXPDTE)
select LOB,MAJPERIL,LOSSCAUSE,NUMERICCL,'0800101' ,'0950930'
from TBTC03 where not EXISTS (select * from TBTC03Y where
TBTC03Y.LOB = TBTC03.LOB AND
TBTC03Y.MAJPERIL = TBTC03.MAJPERIL AND
TBTC03Y.LOSSCAUSE = TBTC03.LOSSCAUSE AND
TBTC03Y.NUMERICCL = TBTC03.NUMERICCL)
The primary key for both the tables is LOB, MAJPERIL and LOSSCAUSE.
However i have some TBTC03Y records, that already have the data with the primary key.
Firing the above query gives primary key constraints on some of the rows.
I am unable to figure out how i can acomplish it.
The issue with the primary key is that you're also including NUMERICCL in the WHERE clause. If you remove this you'll then be inserting unique data.
You may have to create a separate process as it appears you have some records in each table that have the same LOB, MAJPERIL and LOSSCAUSE but have a different NUMERICCL. I can think of three options here;
You have an issue with the data that needs fixing.
Maybe you want to update this value to match, in which case you're looking at an UPDATE rather than INSERT INTO.
You need to update your composite primary key to include the column NUMERICCL.
Removing NUMERICCL from the where clause would also correct this.
If the PK for both tables is {LOB, MAJPERIL, LOSSCAUSE}, you should remove TBTC03Y.NUMERICCL = TBTC03.NUMERICCL from your where clause.
Example:
t1{LOB, MAJPERIL, LOSSCAUSE, NUMERICCL}
1 1 1 1
t2{LOB, MAJPERIL, LOSSCAUSE, NUMERICCL}
1 1 1 2
In t2 there is no row where:
TBTC03Y.LOB = TBTC03.LOB AND
TBTC03Y.MAJPERIL = TBTC03.MAJPERIL AND
TBTC03Y.LOSSCAUSE = TBTC03.LOSSCAUSE AND
TBTC03Y.NUMERICCL = TBTC03.NUMERICCL
But inserting will obvioulsy violate PK constraint in t2:
t2{LOB, MAJPERIL, LOSSCAUSE}
1 1 1

Converting Pseudocode to SQL Script

So I have two tables:
Bookmarks has a few columns [id, etc.]
Person_Bookmark has 2 columns [personId, bookmarkId]
Bookmarks represents links to other websites. All valid bookmarks have an id. The Person_Bookmark table has a bunch of personIds and their bookmarks, shown as bookmarkId.
Here's my pseudocode:
> let x = integer list of all bookmarkId's from Person_Bookmark
>
> for each x {
> if ('select * from 'Bookmarks' where 'id' = x returns 0 rows) {
> delete from 'person_bookmark' where 'bookmarkId' = x
> }
> }
Please advise me how to convert to a Postgres [edit] SQL script.
#Jan mentioned foreign keys already, but his advice is incomplete.
Seems like you want to delete all associations to a bookmark that does not exist (any more).
Define a foreign key constraint in the form of:
ALTER TABLE person_bookmarks
ADD CONSTRAINT pb_fk FOREIGN KEY (bookmarkid) REFERENCES bookmarks (id)
ON UPDATE CASCADE
ON DELETE CASCADE;
This only allows values in person_bookmarks.bookmarkid that exist in bookmarks.id.
ON UPDATE CASCADE changes corresponding values in person_bookmarks.bookmarkid when you change an entry in bookmarks.id
ON DELETE CASCADE deletes corresponding rows in person_bookmarks.bookmarkid when you change an entry in bookmarks.id.
Other options are available, read the manual.
The ON DELETE CASCADE clause does automatically, what you are trying to fix manually. Before you can add the fk constraint you'll have to fix it manually once:
DELETE FROM person_bookmarks pb
WHERE NOT EXISTS (SELECT 1 FROM bookmarks b WHERE b.id = pb.bookmarkid);
-- OR NOT EXISTS (SELECT 1 FROM persons p WHERE p.id = pb.personid);
Deletes all rows with non-existing bookmarkid. Uncomment the last line to get rid of dead persons, too.
This works in SQL Server - not sure about MySQL...
delete pb
from
person_bookmark pb
where not exists (select 1 from booksmarks b where b.id = pb.bookmarkid)
Another version of #Derek's reply:
DELETE FROM person_bookmark
WHERE bookmarkid NOT IN (SELECT id FROM bookmarks)
The need to do this implies that you have no foreign key indexes between your tables. I strongly advise you to do so. The drawback (or feature) lies in that when you for example delete a person (I'm guessing this table exists from your example), you have to delete all associated data first, otherwise the server will throw an error.
Something like this:
DELETE FROM person_Bookmark WHERE personid = #personid
DELETE FROM person_SomeOtherTable WHERE personid = #personid
DELETE FROM person WHERE id = #personid
The advantage though is that you'll have no orphan rows in your database, and you can't enter erroneous data by mistake (store a bookmark for a person that doesn't exist).

Update a primary key without triggering unique key violation

I just came to this very simple situation where I needed to shift a primary key up a certain value. Suppose the following table:
CREATE TABLE Test (
Id INTEGER PRIMARY KEY,
Desc TEXT);
Loaded with the following values:
INSERT INTO Test VALUES (0,'one');
INSERT INTO Test VALUES (1,'two');
If there's an attempt at updating the primary key, it will, of course, fail:
UPDATE Test SET Id = Id+1;
Error: column id is not unique
Is there some way to suspend unicity check until after the update query has run?
Find a nice pivot point, and move the data around that pivot. For example, if all your IDs are positive, a good pivot is 0.
When you would normally do
UPDATE Test SET Id = Id+1;
Do this sequence instead
UPDATE Test SET Id = -Id;
UPDATE Test SET Id = -Id +1;
For times, you can find a similar pivot point, but the formula is just a tad harder.
without understanding the fundamental problem (and yeah, you seem like a victim of code and run on this one!), multiplying the ID by the largest value in the table should work.
update test
set id = id * (select max(id) + 1 from test)
However, it's dirty, and really, databases make it hard to change primary keys for a reason...
OK. Second attempt. Try this:
Get the MAX of the key column.
UPDATE table SET key = key + max + 1
UPDATE table SET key = key - max
This will avoid duplicated keys at any time in the update process by moving the window far enough.