Copy data from a column in some rows to another column in other rows in oracle - oracle

quite the same question as here : Copy data from one existing row to another existing row in SQL?
but in Oracle, where update ... from and update t1, t2 are not supported.
I'll repeat it here in my own words ;
I have a table T, which looks like this :
and as the arrow shows it, I want to copy everything from r where c = 1 to e where c = 2, with t matching.
I have the select statement to get what I want to copy :
select
told.t,
told.r
from
T told
inner join
T tnew
on
told.t= tnew.t
where
told.c = 1
and
tnew.c = 2
I just don't know how to put this together in an update. An Oracle update, specifically.

try this:
update T tnew
set tnew.e = (select told.r from T told where told.c = 2 and told.t = tnew.t)
where tnew.c = 1

Sounds like the time for a bulk collects! Not as pretty as AB Cade's solution but more efficient.
declare
c_data is
select t1.rowid as rid, t2.r
from my_table t1
join my_table t2
on t1.t = t2.t
where t1.c = 2
and t2.c = 1
;
type t__data is table of c_data index by binary_integer;
t_data t__data;
begin
open c_data;
loop
fetch c_data bulk collect into t_data limit 25000;
exit when t_data.count = 0;
forall i in t_data.first .. t_data.last loop
update my_table
set e = t_data(i).r
where rowid = t_data(i).rid
;
commit;
end loop;
close c_data;
end;
/

Related

Update using loop in Oracle

BEGIN
FOR J IN (select DISTINCT S_NUMBER from WMWHSE3.NUMBER_SHIPTO)
LOOP
UPDATE wmwhse3.orders
SET
orders.susr4 = (select S_NUMBER from WMWHSE3.NUMBER_SHIPTO where S_NUMBER = J)
where orders.c_company = (select SHIPTO from WMWHSE3.NUMBER_SHIPTO where S_NUMBER = J)
and orders.orderkey in (SELECT a.orderkey FROM wmwhse3.orders a INNER JOIN wmwhse3.wavedetail b ON a.orderkey = b.orderkey where b.wavekey = '0000000086');
END LOOP;
END;
Looks like you're overcomplicating things (and making everything slower than it should be, as row-by-row processing (in a loop) is usually much slower than set processing).
Therefore, how about a single update, without PL/SQL? Something like this:
update orders o set
o.susr4 = (select n.s_number
from number_shipto n
where n.shipto = o.c_company
)
where exists (select null from wavedetail b
where b.orderkey = o.orderkey
and b.wavekey = '0000000086'
);

I'm trying to update 2 fields in multiple tables in my database using a trigger after inserting a new row

i just created the trigger
here is the code:
CREATE OR REPLACE TRIGGER tr_update_solde_nbreserv
AFTER INSERT ON reservation
FOR EACH ROW
BEGIN
UPDATE CLIENTS
SET CLIENTS.NB_RESERV = NB_RESERV+1 , CLIENTS.SOLDE = SOLDE+1
FROM dbo.clients as c
INNER JOIN dbo.reservation as r
ON c.numc = r.numc
WHERE r.numr = :new.numr;
BEGIN
SELECT fillHist_station FROM DUAL;
END;
end tr_update_solde_nbreserv;
i'm getting these 2 errors:
Error(1,9): PL/SQL: SQL Statement ignored
Error(3,9): PL/SQL: ORA-00933: SQL command not properly ended
how can i fix them
There are several issues with your trigger code.
1) The purpose of this part of the code is unclear :
BEGIN
SELECT fillHist_station FROM DUAL;
END;
fillHist_station is not declared, hence this code would raise an invalid identifier error.
2) The syntax of the UPDATE query is invalid. Also, your intend is to select from the table that the trigger fired on, which is not allowed in Oracle. From looking at your code, it looks like you don't actually need to query RESERVATION to achieve your goal. As a row was just inserted in RESERVATION, you already know the corresponding client number.
3) You miss a / at the end
Here is an updated version of your code, that you can play around with in this db fiddle (you did not provide the structure of your tables so I just created the coulmns that are referenced in the query) :
CREATE OR REPLACE TRIGGER tr_update_solde_nbreserv
AFTER INSERT ON RESERVATION
FOR EACH ROW
BEGIN
UPDATE CLIENTS
SET NB_RESERV = NB_RESERV+1 , SOLDE = SOLDE+1
WHERE numc = :new.numc;
END tr_update_solde_nbreserv;
/
update CLIENTS
SET CLIENTS.NB_RESERV = NB_RESERV+1 , CLIENTS.SOLDE = SOLDE+1
FROM dbo.clients as c
inner join dbo.reservation as r
on c.numc = r.numc
where r.numr = :new.numr;
update with inner join is not supported in Oracle database in this way. furthermore dbo.clients and dbo.reservations look like Sql Server tables rather then oracle.
I believe that you are looking for something like this, but I am not sure about the relations. You may need to fix the query.
UPDATE
(
SELECT clients.nb_reserv, r.nb_reserv as r_nb_reserv, clients.solde, r.solde as r_solde
FROM clients
inner join reservation as r
on c.numc = r.numc
where r.numr = :new.numr
) t
SET CLIENTS.NB_RESERV = r_nb_reserv + 1, clients.solde = r_solde+1;
Simpler approach
UPDATE clients SET NB_RESERV = (SELECT nb_reserv +1
FROM reservations
WHERE c.numc = r.numc and r.numr = :new.numr),
SOLDE = (SELECT SOLDE +1
FROM reservations
WHERE c.numc = r.numc and r.numr = :new.numr)
WHERE EXISTS (SELECT 1 FROM reservations
WHERE c.numc = r.numc and r.numr = :new.numr);

Cursor loop update Table by many values

DECLARE
CURSOR contacts
IS
SELECT SUM (budget) AS budget
FROM et_bp_gl_account a, et_bp_fact f
WHERE f.gl_account_id = a.gl_account_id
AND total_flag = 0
GROUP BY month_id, org_unit_id;
BEGIN
FOR r IN contacts
LOOP
UPDATE et_bp_fact
SET budget = r.budget
WHERE gl_account_id IN (SELECT total_element
FROM et_bp_gl_account g, et_bp_fact f
WHERE f.gl_account_id = g.gl_account_id);
END LOOP;
END;
I want to update the table ET_BP_FACT by many values example(25,50,75)
returned from Cursor but when i execute the table updated by (25,25,25)
I think there an issue in the loop
That's because the UPDATE's WHERE clause doesn't "reference" cursor's values. Something like this:
DECLARE
CURSOR contacts
IS
SELECT month_id, org_unit_id, --> include additional columns here ...
SUM (budget) AS budget
FROM et_bp_gl_account a, et_bp_fact f
WHERE f.gl_account_id = a.gl_account_id
AND total_flag = 0
GROUP BY month_id, org_unit_id;
BEGIN
FOR r IN contacts
LOOP
UPDATE et_bp_fact
SET budget = r.budget
WHERE gl_account_id IN
(SELECT total_element
FROM et_bp_gl_account g, et_bp_fact f
WHERE f.gl_account_id = g.gl_account_id
--
AND f.org_unit_id = r.org_unit_id --> ... and reference them here ...
AND g.month_id = r.month_id);
--> ... or, possibly, here
END LOOP;
END;
I'd suggest you to always precede column names with table aliases, because - looking at your code, there's no way to guess which table(s) MONTH_ID and ORG_UNIT_ID belong to, so my code might (or might not) work, but I hope you got the general idea.

PLSQL Loop taking lot of time to execute

I have a Oracle procedure which is updating below 10,000 records. if I run the normal SQL statement, it is returning the result immediately with in seconds(30).
same statment in procedure loop it is going to endlessly.
My loop statment below.
Note: data FIELD Data type is a clob not varchar2.
statment:
select
'LB_COPY_CHANGE-'||8 LAST_MODIFIED_BY,
rec.COR_ID_old,
rec.COR_ID_NEW,
replace(replace(replace(a.data,'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||','),''id':'||rec.COR_ID_OLD||',',''id':'||rec.COR_ID_NEW||','),'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||',') as data
from KPI_MET_FIELD_DATA a, CUSTOM_TEMP_TABLE_SESSION_1 rec
where A.cmf_fk_id in (145,146,147)
and TYPE_LB in (14,15,16)
and a.KDB_FK_ID in (
select distinct km.KDB_FK_ID
from KPI_MET_FIELD_DATA km , KPI_DET_BASE kp, KPI_REL_KPI_SCORECARD ksc, STR_DET_EMP_SCORECARD sc
where ksc.SDE_FK_ID=sc.SDE_PK_ID
and km.KDB_FK_ID = ksc.KDB_KPI_FK_ID
and km.is_deleted=0
and kp.kdb_pk_id = km.KDB_FK_ID
and kp.is_deleted=0
and km.cmf_fk_id in (145,146,147)
and sc.sdp_fk_id = 8)
and a.is_deleted=0
and (a.data like '%'||rec.COR_ID_OLD||'%');
FOR rec in (SELECT * FROM CUSTOM_TEMP_TABLE_SESSION where TYPE_LB in (14,15,16)) LOOP
update KPI_MET_FIELD_DATA
set LAST_MODIFIED_BY='LB_COPY_CHANGE-'||p2 ,
data = replace(replace(replace(data,'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||','),''id':'||rec.COR_ID_OLD||',',''id':'||rec.COR_ID_NEW||','),'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||',')
where cmf_fk_id in (145,146,147)
and KDB_FK_ID in (
select distinct km.KDB_FK_ID
from KPI_MET_FIELD_DATA km , KPI_DET_BASE kp, KPI_REL_KPI_SCORECARD ksc, STR_DET_EMP_SCORECARD sc
where ksc.SDE_FK_ID=sc.SDE_PK_ID
and km.KDB_FK_ID = ksc.KDB_KPI_FK_ID
and km.is_deleted=0
and kp.kdb_pk_id = km.KDB_FK_ID
and kp.is_deleted=0
and km.cmf_fk_id in (145,146,147)
and sc.sdp_fk_id = p2)
and is_deleted=0 ;
There are several weaknesses in your code.
WHERE KDB_FK_ID in (select distinct ... does not make any sense. There is no need to make DISTINCT for an IN () clause.
Use ANSI join syntax instead of old Oracle join syntax, it is less error-prone
But the main difference is, your loop does not contain join condition (a.data like '%'||rec.COR_ID_OLD||'%'), i.e. you update entire table KPI_MET_FIELD_DATA again and again for each row in CUSTOM_TEMP_TABLE_SESSION where TYPE_LB in (14,15,16)

Oracle Merge statement error in procedure package body

I'm struggling trying to make this procedure to work, I have the following code inside my package body:
PACKAGE BODY PKG_DM_TRANS_DIMENSIONES AS
PROCEDURE SP_DM_TRANS_DIM_CUENTA AS
vNumRegistrosDimCuentas NUMBER;
BEGIN
SELECT COUNT(*) INTO vNumRegistrosDimCuentas
FROM DIM_CUENTAS;
IF (vNumRegistrosDimCuentas <> 0) THEN
MERGE INTO DIM_CUENTAS DIMC
USING (
SELECT * FROM (
SELECT
DIM.FNT_CUENTA_ID AS DIM_CUENTA_ID,
C.CUE_ID AS FNT_CUENTA_ID,
R.REG_REGION AS REGION,
P.PAI_PAIS AS PAIS,
E.EDI_NOMBRE_EDIFICIO AS EDIFICIO,
C.CUE_CUENTA,
TIC.TIC_TIPO_CONTACTO,
C.CUE_STATUS,
CASE
WHEN DIM.FNT_CUENTA_ID IS NULL THEN 1
WHEN
R.REG_REGION <> DIM.REGION OR
P.PAI_PAIS <> DIM.PAIS OR
E.EDI_NOMBRE_EDIFICIO <> DIM.EDIFICIO OR
C.CUE_CUENTA <> DIM.CUENTA OR
TIC.TIC_TIPO_CONTACTO <> DIM.TIPO_CONTACTO
THEN 2
ELSE 0
END AS TIPO_FILA
FROM STA_EDIFICIOS_EXTRACCION E
LEFT JOIN
STA_PAISES_EXTRACCION P ON E.EDI_PAI_ID = P.PAI_ID
LEFT JOIN
STA_REGIONES_EXTRACCION R ON P.PAI_REG_ID = R.REG_ID
LEFT JOIN
EUB_EDIFICIO_UBICACION EUB ON EUB.EUB_EDI_ID = E.EDI_ID
LEFT JOIN
STA_CUENTAS_EXTRACCION C ON C.CUE_EUB_ID = EUB.EUB_ID
LEFT JOIN
STA_TIPOS_CONTACTO_EXTRACCION TIC ON TIC.TIC_ID = C.CUE_TIC_ID
LEFT JOIN
DIM_CUENTAS DIM ON
(C.CUE_ID = DIM.FNT_CUENTA_ID AND DIM.CUENTA_STATUS = 1)
)
) Q
ON (DIMC.FNT_CUENTA_ID = Q.TIPO_FILA)
WHEN MATCHED THEN
INSERT (DIMC.REGION, DIMC.PAIS, DIMC.EDIFICIO, DIMC.CUENTA, DIMC.TIPO_CONTACTO, DIMC.CUENTA_FECHA_CREACION, DIMC.FNT_CUENTA_ID)
VALUES (Q.REGION, Q.PAIS, Q.EDIFICIO, Q.CUE_CUENTA, Q.TIC_TIPO_CONTACTO, TO_TIMESTAMP(sysdate, 'MM/DD/YYYY HH24:MI:SS'), Q.FNT_CUENTA_ID)
WHEN NOT MATCHED THEN
UPDATE SET DIMC.CUENTA_STATUS = 0 WHERE DIMC.CUENTA_STATUS = 1 -- <- dummy update stmt
ELSE ..... -- else statement code working fine...
END IF;
END SP_DM_TRANS_DIM_CUENTA;
END PKG_DM_TRANS_DIMENSIONES;
I'm getting erros at the line
MERGE INTO DIM_CUENTAS DIMC
Saying "Statement ignored"
and then, another error at:
INSERT (DIMC.REGION, DIMC.PAIS, DIMC.EDIFICIO, DIMC.CUENTA, DIMC.TIPO_CONTACTO, DIMC.CUENTA_FECHA_CREACION, DIMC.FNT_CUENTA_ID)
VALUES (Q.REGION, Q.PAIS, Q.EDIFICIO, Q.CUE_CUENTA, Q.TIC_TIPO_CONTACTO, TO_TIMESTAMP(sysdate, 'MM/DD/YYYY HH24:MI:SS'), Q.FNT_CUENTA_ID)
saying "missing keyword". Is it possible to use the merge statement in a SP? I'm new to Oracle so I really don't know if what I'm trying to do is possible or if there's something wrong with my code.
Thanks for any help, I would really appreaciate it.
I think that you swapped commands - after when matched you should put update statement and after not matched - insert.
Similar example worked for me, but after swapping statements I got ORA-00905 missing keyword. So correct version is:
merge into t1
using (select * from t2) t2 on (t1.id = t2.id)
when matched then update set t1.name = t2.name
when not matched then insert (id, name) values (t2.id, t2.name)

Resources