Oracle - deleting duplicates - oracle

I have found the following way for removing duplicates:
DELETE FROM
table_name A
WHERE
a.rowid >
ANY (
SELECT
B.rowid
FROM
table_name B
WHERE
A.col1 = B.col1
AND
A.col2 = B.col2
);
Could someone explain me step by step how does the query works?
TIA!

In Oracle, ROWID is a pseudo column points to the physical location of a row. The query does a self join and fetches those rows which have the same value of column 1 & column 2 - with the assumption that these keys are enough to identify as duplicate row.
Once the rows are fetched, the query then deletes those rowids which are larger than the first row fetched, thereby deleting duplicates

Like this:
DELETE FROM // The command to delete
table_name A //the table in which you want to remove duplicate
WHERE //condition
a.rowid > //checking the rowid which oracle adds to each row. Oracle Database rowid values contain information necessary to locate a row.
ANY ( //any row which has a condition
SELECT //select
B.rowid //rowid
FROM //from
table_name B //table name with alias name as B. Is used for making a self join
WHERE //condition
A.col1 = B.col1 //where the column1 has the same rowid
AND //and
A.col2 = B.col2 //where the column2 has the same rowid
);

Related

Oracle MINUS operator and delete

You can insert records into table B if they are in table A
insert into B
select * from A
minus
select * from B
How do you delete records that are in B and not in A?
select * from B
minus
select * from A
How to delete records?
The assumption is that we do not have a primary key or a unique one.
You can do it like this:
delete from a2
where (COLUMN1, COLUMN2, COLUMN3, ...) in (select * from a2
minus
select * from a1);
It works, but you have to enter the column names in the where clause. Can not do delete in such a beautiful way as insert into select * from ...?
If you wanted to continue with your current approach, you should not use select * in your minus query. Rather, you should always explicitly list out the columns which you want to use.
But, I would use an EXISTS query here:
DELETE
FROM tableB b
WHERE NOT EXISTS (SELECT 1 FROM tableA a
WHERE a.col1 = b.col1 AND
a.col2 = b.col2 AND
a.col3 = b.col3 AND ...);
Best practice going forward would to have a primary key column in the A table. Then, you would only need to check that column against the B table for uniqueness.

Add another Table in Where Clause

I am using Oracle DB.
I have a static query like
SELECT * FROM TESTSCHEMA.TABLE_A WHERE LOAN_ID = :LOAN_ID
The remaining where condition is coming from a table .
Now we came across a scenario where we need to introduce a new table if one column in TABLE_A is NULL i need to take value from TABLE_B
We are not looking for a code change or deployment , instead if we can update in table .
SELECT
*
FROM
TESTSCHEMA.TABLE_A
WHERE
LOAN_ID = :LOAN_ID
AND
(
/* if COLUMNA is NULL in TABLE_A
then i need to pull value from TABLE_B in the same select statement */
)
My interpretation...
If you're wanting to limit the data returned based on columnA when it has a value, but when it doesn't have a value (NULL) use columnB from table B... to limit by it; then coalesce & a sub query should do it.
Or you could replace the whole subquery with a scalar function and call it.
SELECT *
FROM TESTSCHEMA.TABLE_A
WHERE LOAN_ID = :LOAN_ID
AND COALESCE(COLUMNA,(SELECT ColumNName
FROM table_B
WHERE [Some Limits to get 1 record always]) = DesiredValue
Replace ColumnName with desired column from table_B
Replace DesiredValue with value you want to compare columnA, or ColumnB to.
Add Where clause limits to table_B to ensure you only get 1 record back always.
Or...
SELECT *
FROM TESTSCHEMA.TABLE_A
WHERE LOAN_ID = :LOAN_ID
AND COALESCE(COLUMNA,GetBValueWhenAValueNull(Paramaters?)) = DesiredValue
But as that would require a deployment/code change... guessing not
What you can do is remove the NULL values from tableA
UPDATE TABLE_A
SET value = (SELECT TABLE_B.value
FROM TABLE_B
WHERE TABLE_A.LOAN_ID = TABLE_B.LOAN_ID )
WHERE LOAN_ID = :LOAN_ID
AND value is NULL

Oracle 20 million update based on join

I have a need to do the following
UPDATE TABLE2 t2
SET t2.product_id = (select t1.product_id from
table1 t1 where t1.matching_id = t2.matching_id)
Except that TABLE2 has 27 million records. The product_id is a newly added column and hence populating data to it.
I could use a cursor , break down my record set in TABLE2 to a reasonably smaller number, But with 27 million records, I am not sure whats the best way.
Pl suggest, even if it means exporting my data to excel.
Update - THe matching columns are indexed too.
The only thing I could do different is replace the update for a CREATE TABLE AS
CREATE TABLE table2_new AS
SELECT t2.* (less product_id), t1.product_id
FROM table1 t1
JOIN table2 t2
ON t1.matching_id = t2.matching_id
But later you will have to add the CONSTRAINTS manually, delete table2 and replace for table2_new
update (select t1.product_id as old_product_id, t2.product_id as new_product_id
from table1 t1
join table2 t2 on (t1.matching_id = t2.matching_id)) t
set t.new_product_id = t.old_product_id

How to update multiple rows include with-select sentence in Oracle

I want update table_a 's col1 with a value from another table.
I make a select that is
with tmp as (
blar~
)
select col1 from table_b b, tmp t
where 1=1
and b.col2 = t.col_x
Update join condition
table_a.col3 = table_b.col3
The principle is to create an updateable view like this:
update
( with tmp as ( select col2
from table_c)
select a.col1 as a_col1
, b.col1 as b_col1
, a.id as a_id
from tmp
join table_b b
on b.col2 = tmp.col2
join table_a a
on a.col3 = b.col3
) t
set a_col1 = b_col1
/
The important points are:
we only update one table from the view;
all the other tables in the view have primary or unique keys so they are guaranteed to return only one row.
the unique columns must be referenced in the view
If the update does not fulfil these strictures it will hurl ORA-01779: cannot modify a column which maps to a non key-preserved table.
It's not clear why you want to use a WITH clause but that may make it harder to ensure you're using key-preserved tables. For instance this variant on the above query fails, even though we know DUAL always returns one row.
update
( with tmp as ( select c.col2
from table_c c
join dual d
on d.dummy = c.col2)
select a.col1 as a_col1
, b.col1 as b_col1
, a.id as a_id
from tmp
join table_b b
on b.col2 = tmp.col2
join table_a a
on a.col3 = b.col3
) t
set a_col1 = b_col1
/
If this explanation does not help you arrive at a solution please edit your question to provide more details. Include any error messages you get. "i can't success" is not enough information for us to help you.
"I was use your answer that called /*+ bypass_ujvc */ "
That is an undocumented hint, so it's pretty risky to use in Production. Also, it seems Oracle removed it in 11gR2 and later, so it won't have any effect (which is why using undocumented hints is risky). You should find a solution which works without the hint.
It's hard to help as you didn't provide enough information. However with result can be update in below way:
update (
with temp as (
select col1 from table_a
)
select col1 from temp )
set col1 = 'newValue'

How to update a table with null values with data from other table at one time?

I have 2 tables - A and B . Table A has two columns, pkey (primary key) and col1. Table B also has two columns, pr_key (primary key but not a foreign key) and column1. Both tables have 4 rows. Table B has no values in column1, while table A has column1 values for all 4 rows. So my data looks like this
Table A
pkey col1
A 10
B 20
C 30
D 40
Table B
pr_key column1
A null
B null
C null
D null
I want to update table B to set the column1 value of each row equal to the column1 value of the equivalent row from table A in a single DML statement.
Should be something like that (depends on SQL implementation you use, but in general, the following is rather standard. In particular should work in MS-SQL and in MySQL.
INSERT INTO tblB (pr_key, column1)
SELECT pkey, col1
FROM tblA
-- WHERE some condition (if you don't want 100% of A to be copied)
The question is a bit unclear as to the nature of tblB's pr_key, if for some reason this was a default/auto-incremented key for that table, it could just then be omitted from both the column list (in parenthesis) and in the SELECT that follows. In this fashion upon insertion of each new row, a new value would be generated.
Edit: It appears the OP actually wants to update table B with values from A.
The syntax for this should then be something like
UPDATE tblB
SET Column1 = A.Col1
FROM tblA AS A
JOIN tblB AS B ON B.pr_key = A.pkey
This may perform better:
MERGE INTO tableB
USING (select pkey, col1 from tableA) a
ON (tableB.pr_key = a.pkey)
WHEN MATCHED THEN UPDATE
SET tableB.column1 = a.col1;
It sounds like you want to do a correlated update. The syntax for that in Oracle is
UPDATE tableB b
SET column1 = (SELECT a.column1
FROM tableA a
WHERE a.pkey = b.pr_key)
WHERE EXISTS( SELECT 1
FROM tableA a
WHERE a.pkey = b.pr_key )
The WHERE EXISTS clause isn't necessary if tableA and tableB each have 4 rows and have the same set of keys in each. It is much safer to include that option, though, to avoid updating column1 values of tableB to NULL if there is no matching row in tableA.

Resources