I have two tables, one parent and one child table. Child will have many rows for parent_id. Both table has status column. Possible values are Active and Deleted.
I want to do this. If for a parent id all children have Deleted status, have to mark parent also as Deleted from Active status. Can it be done in single update query?
Thanks in advance.
How about something like this?
UPDATE parent_table pt SET deleted = 'Y' WHERE deleted = 'N' AND id NOT IN
(SELECT parent_id FROM child_table ct WHERE deleted = 'N' AND ct.parent_id = pt.id)
Yes:
update parent
set status = 'Deleted'
where status = 'Active'
and not exists ( select null from child
where child.id = parent.id
and child.status <> 'Deleted')
UPDATE parent_table
set status = 'deleted'
WHERE status = 'active'
AND id in (
SELECT parent_id
FROM (
SELECT
parent_id
, count(*) total
, sum (CASE staus WHEN 'deleted' THEN 1 ELSE 0 END) deleted
FROM child_table
group by parent_id
)
WHERE total = deleted
)
Related
I want to Delete the Duplicates from the table update the unique identifier and merge it with the already existing record.
I have a table which can contain following records -
ID Name Req_qty
1001 ABC-02/01+Time 10
1001 ABC-03/01+Time 20
1001 ABC 30
1002 XYZ 40
1003 DEF-02/01+Time 10
1003 DEF-02/01+Time 20
And I am expecting the records after the operation as follows:
ID Name Req_Qty
1001 ABC 60
1002 XYZ 40
1003 DEF 30
Any assistance would be really helpful. Thanks!
It is possible to do this in a single SQL statement:
merge into (select rowid as rid, x.* from test_table x ) o
using ( select id
, regexp_substr(name, '^[[:alpha:]]+') as name
, sum(reg_qty) as reg_qty
, min(rowid) as rid
from test_table
group by id
, regexp_substr(name, '^[[:alpha:]]+')
) n
on (o.id = n.id)
when matched then
update
set o.name = n.name
, o.reg_qty = n.reg_qty
delete where o.rid > n.rid;
Working example
This uses a couple of tricks:
the delete clause of a merge statement will only operate on data that has been updated, and so there's no restriction on what gets updated.
you can't select rowid from a "view" and so it's faked as rid before updating
by selecting the minimum rowid from per ID we make a random choice about which row we're going to keep. We can then delete all the rows that have a "greater" rowid. If you have a primary key or any other column you'd prefer to use as a discriminator just substitute that column for rowid (and ensure it's indexed if your table has any volume!)
Note that the regular expression differs from the other answer; it uses caret (^) to anchor the search for characters to the beginning of the string before looking for all alpha characters thereafter. This isn't required as the default start position for REGEXP_SUBSTR() is the first (1-indexed) but it makes it clearer what the intention is.
In your case, you will need to update the records first and then delete the records which are not required as following (Update):
UPDATE TABLE1 T
SET T.REQ_QTY = (
SELECT
SUM(TIN.REQ_QTY) AS REQ_QTY
FROM
TABLE1 TIN
WHERE TIN.ID = T.ID
)
WHERE (T.ROWID,1) IN
(SELECT TIN1.ROWID, ROW_NUMBER() OVER (PARTITION BY TIN1.ID)
FROM TABLE1 TIN1); --TAKING RANDOM RECORD FOR EACH ID
DELETE FROM TABLE1 T
WHERE NOT EXISTS (SELECT 1 FROM TABLE1 TIN
WHERE TIN.ID = T.ID AND TIN.REQ_QTY > T.REQ_QTY);
UPDATE TABLE1 SET NAME = regexp_substr(NAME,'[[:alpha:]]+');
--Update--
The following merge should work for you
MERGE INTO
(select rowid as rid, T.* from MY_TABLE1 T ) MT
USING
(
SELECT * FROM
(SELECT ID,
regexp_substr(NAME,'^[[:alpha:]]+') AS NAME_UPDATED,
SUM(Req_qty) OVER (PARTITION BY ID) AS Req_qty_SUM,
ROWID AS RID
FROM MY_TABLE1) MT1
WHERE RN = 1
) mt1
ON (MT.ID = MT1.ID)
WHEN MATCHED THEN
UPDATE SET MT.NAME = MT1.NAME_UPDATED, MT.Req_qty = MT1.Req_qty_SUM
delete where (MT.RID <> MT1.RID);
Cheers!!
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
);
I have a table called ‘MainTable’ with following data
Another table called ‘ChildTable’ with following data (foreighn key Number)
Now I want to fetch those records from ‘ChildTable’ if there exists at least one ‘S’ status.
But if any other record for this number id ‘R’ then I don’t want to fetch it
Something like this-
I tried following
Select m.Number, c.Status from MainTable m, ChildTable c
where EXISTS (SELECT NULL
FROM ChildTable c2
WHERE c2.status =’S’ and c2.status <> ‘R’
AND c2.number = m.number)
But here I am getting record having ‘R’ status also, what I am doing wrong?
You can try something like this
select num, status
from
(select id, num, status,
sum(decode(status, 'R', 1, 0)) over (partition by num) Rs,
sum(decode(status, 'S', 1, 0)) over (partition by num) Ss
from child_table) t
where t.Rs = 0 and t.Ss >= 1
-- and status = 'S'
Here is a sqlfiddle demo
The child records with 'R' might be associated with a maintable record that also has another child record with status 'S' -- that is what your query is asking for.
Select
m.Number,
c.Status
from MainTable m
join ChildTable c on c.number = m.number
where EXISTS (
SELECT NULL
FROM ChildTable c2
WHERE c2.status =’S’
AND c2.number = m.number) and
NOT EXISTS (
SELECT NULL
FROM ChildTable c2
WHERE c2.status =’R’
AND c2.number = m.number)
WITH ChildrenWithS AS (
SELECT Number
FROM ChildTable
WHERE Status = 'S'
)
,ChildrenWithR AS (
SELECT Number
FROM ChildTable
WHERE Status = 'R'
)
SELECT MaintTable.Number
,ChildTable.Status
FROM MainTable
INNER JOIN ChildTable
ON MainTable.Number = ChildTable.Number
WHERE MainTable.Number IN (SELECT Number FROM ChildrenWithS)
AND MainTable.Number NOT IN (SELECT Number FROM ChildrenWithR)
I have an ORACLE query which does not work for this query.
UPDATE emp a set a.Enq_Status = 'PROGRESS'
where exists (select * from emp a, Data b
WHERE a.SA_Enq_Status is NULL
and a.EQ_Status = 'ACTIVATED'
and a.Activation_Return_Code = 0
and a.Alert_Code > 0
and a.User_Id = b.User_Id
and (b.Is_Associate is NULL or b.Is_Associate = 0)
and (b.Stk_Schd is NULL)
and (b.Stk_Dis_Amt is NULL)
);
My Problem is I want to update mutiple records in the table emp (A) to status to 'PROGRESS'.But when executing this query all records in a.Enq_status is changes.Please help me in this.Updation is not correct.Please help me in this
You have specified table emp both in the update query and the subquery too, Oracle will treat these as seperate tables.
You need a correlated subquery:
UPDATE emp a
set a.Enq_Status = 'PROGRESS'
where exists (select 'X'
from Data b
WHERE a.SA_Enq_Status is NULL
and a.EQ_Status = 'ACTIVATED'
and a.Activation_Return_Code = 0
and a.Alert_Code > 0
and a.User_Id = b.User_Id
and (b.Is_Associate is NULL or b.Is_Associate = 0)
and (b.Stk_Schd is NULL)
and (b.Stk_Dis_Amt is NULL));
You could probably just update the emp table without the need for the subquery though if you link to the Data table in the where clause...
Your update statement will update all the records in emp table because you don't specify the records to update. If your sub-query returns at least one row, the all the emp records will be updated. If it returns no rows, then none of the records will be updated.
Change your update like this:
UPDATE emp SET Enq_Status = 'PROGRESS'
WHERE id in
(SELECT a.id
FROM emp a, Data b
WHERE a.SA_Enq_Status is NULL and a.EQ_Status = 'ACTIVATED'
and a.Activation_Return_Code = 0 and a.Alert_Code > 0
and a.User_Id = b.User_Id and (b.Is_Associate is NULL or b.Is_Associate = 0)
and (b.Stk_Schd is NULL)and (b.Stk_Dis_Amt is NULL)
);
Try:
UPDATE emp a
SET a.enq_status = 'PROGRESS'
WHERE a.sa_enq_status IS NULL
AND a.eq_status = 'ACTIVATED'
AND a.activation_return_code = 0
AND a.alert_code > 0
AND EXISTS
(SELECT 'X'
FROM data b
WHERE a.user_id = b.user_id
AND ( b.is_associate IS NULL OR b.is_associate = 0 )
AND b.stk_schd IS NULL
AND b.stk_dis_amt IS NULL);
I have two tables with same columns. i want to update table1 records whose status is 'Linked' by the corresponding values from table2.
table 1
ID STATUS VOUCHER
'T010000020 Not Linked null
'T010000021 Linked null
'T010000024 Not Linked null
'T010000026 Linked null
table 2
ID STATUS VOUCHER
'T010000020 Not Linked null
'T010000021 Linked 11234
'T010000024 Not Linked null
'T010000026 Linked 5423
UPDATE Table1 t1
SET Voucher = (SELECT Voucher FROM
Table2 t2 WHERE t2.Id = t1.Id
and t2.Status = 'Linked')
WHERE Status = 'Linked'