Insert the record in one table from another table with some criteria in oracle - oracle

I need to insert the record into one table from another table which is exact replica of other table ,condition for putting this as when a same record (for certain condition match) is coming from another table it will update the existing record and when a brand new record come it will insert the record.
I have written the query for this as below please correct me if possible.
INSERT INTO TEMP1 (B,C,D,PROVIDER_ID,NATIONAL_PROVIDER_IDENTIFIER,TAXONIMY_CODE,F,G,H)
SELECT W.B,W.C,W.D,W.PROVIDER_ID,W.NATIONAL_PROVIDER_IDENTIFIER,W.TAXONIMY_CODE,W.F,W.G,W.H
FROM TEMP2 W LEFT JOIN TEMP1 A ON( A.provider_id = W.provider_id
AND A.NATIONAL_PROVIDER_IDENTIFIER = W.NATIONAL_PROVIDER_IDENTIFIER
AND A.TAXONOMY_CODE = W.TAXONOMY_CODE)
WHERE W.SOURCE_ID = 'COSMOS'

It's still a bit unclear to me, but it does sound like you want to be using a MERGE statement.
If so, your statement would look something like this (hoping I understood your data model)
MERGE INTO TEMP1 a
USING (
SELECT B,C,D,PROVIDER_ID,NATIONAL_PROVIDER_IDENTIFIER,TAXONIMY_CODE,F,G,H
FROM TEMP2
WHERE SOURCE_ID = 'COSMOS'
) w
ON (a.provider_id = w.provider_id AND
a.NATIONAL_PROVIDER_IDENTIFIER = w.NATIONAL_PROVIDER_IDENTIFIER AND
a.TAXONOMY_CODE = w.TAXONOMY_CODE
)
WHEN MATCHED THEN
UPDATE SET a.b = w.b,
a.c = w.c,
a.d = w.d,
a.f = w.f,
a.g = w.g,
a.h = w.h
WHEN NOT MATCHED THEN
INSERT (a.B,a.C,a.D,a.PROVIDER_ID,a.NATIONAL_PROVIDER_IDENTIFIER,a.TAXONIMY_CODE,a.F,a.G,a.H)
VALUES (w.B,w.C,w.D,w.PROVIDER_ID,w.NATIONAL_PROVIDER_IDENTIFIER,w.TAXONIMY_CODE,w.F,w.G,w.H);

Related

Getting ORA-00001 unique constraint violated error when calling a trigger

create or replace TRIGGER "DB"."TRIG_PERIOD_TRUANCY_INS_UPD"
AFTER UPDATE OR INSERT
ON AT_PERIOD_ATTENDANCE_RECORDS
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
BEGIN
IF UPDATING THEN
delete at_period_truancy where period_attendance_records_id = :old.period_attendance_records_id;
END IF;
insert into at_period_truancy (period_attendance_records_id, district_number, school_id, student_id, calendar_date, school_year, minutes)
select :new.period_attendance_records_id, :new.district_number, :new.school_id, :new.student_id, :new.calendar_date, :new.school_year,
(case when :new.attendance_status = 'A' then period.end_time - period.begin_time
when coalesce(:new.tardy_time_in_time, period.begin_time) - period.begin_time >
period.end_time - coalesce(:new.tardy_time_out_time, period.end_time)
then coalesce(:new.tardy_time_in_time, period.begin_time) - period.begin_time
else period.end_time - coalesce(:new.tardy_time_out_time, period.end_time) end)*24*60
from ca_calendar cal
inner join ca_school_calendar calendar
on (cal.district_number = calendar.district_number
and cal.calendar_id = calendar.calendar_id )
inner join sc_class_meeting_pattern meeting
on (calendar.cycle_day_cd = meeting.cycle_day_cd)
inner join sc_class class
on (class.school_scheduling_param_id = meeting.school_scheduling_param_id
and class.class_id = meeting.class_id)
inner join sc_period_info period
on (meeting.school_scheduling_param_id = period.school_scheduling_param_id
and meeting.period = period.period)
where :new.district_number = cal.district_number
and cal.is_active_ind = 1
and :new.school_id = cal.school_id
and :new.school_year = cal.school_year
and :new.calendar_type_cd = cal.calendar_type_cd
and :new.track_number = cal.track_number
and :new.calendar_date = calendar.calendar_date
and :new.school_id = class.school_id
and :new.class_id = class.class_id
and 1 in (select use_in_truancy_report_ind
from enum_at_absence_reason_code
where district_number = :new.district_number
and school_id = :new.school_id
and value = :new.absence_reason_code
union all
select use_in_truancy_report_ind
from enum_at_tardy_reason_code
where district_number = :new.district_number
and school_id = :new.school_id
and value = :new.tardy_reason_code);
END TRIG_PERIOD_TRUANCY_INS_UPD;
This is the trigger that I am using. When calling the update statement this trigger is getting invoked and when I pass tardy_reason_code as UN this error is happening. It executes without any issues if I pass tardy_reason_code with different values.
Trigger is inserting into at_period_truancy tables.
As Oracle raises ORA-00001 (unique constraint violated), it means that you're trying to insert primary key value which already exists in the table.
You didn't post create table statement so it is difficult to guess which columns make the primary key, but - you should know it so check which values you already have in there, compare that to values currently being inserted and you'll know what to do.
Maybe you'll have to modify primary key (add other columns? Abandon idea of current primary key and using a sequence (or identity column)) or the way you're inserting values into the table.

Need bulk update when condition doesn't matches

declare
type employee_t is table of employee%rowtype index by pls_integer;
l_employee_data employee_t;
begin
select *
bulk collect into l_employee_data from employee;
forall indx in 1 .. l_employee_data.count
update roster r
set r.job = l_employee_data(indx).job,
r.position = l_employee_data(indx).position,
r.organisation = l_employee_data(indx).organisation
where r.employee_code = l_employee_data(indx).employee_code;
commit;
end;
In the above example, query updates all the data where it matches employee code with idx value. This is fine. My requirement here is, is it possible to update also, the other rows which doesn't matches employee code with idx value? if yes, then please let me know.
Update with what, if employee code doesn't match? If there's no match, then there's no match. You could update those columns with some value, but the question is which.
Besides, instead of what you used, consider a single MERGE statement:
merge into roster r
using employee e
on (e.employee_code = r.employee_code)
when matched then update set
r.job = e.job,
r.position = e.position,
r.organisation = e.organisation;

Oracle trying to update a table by joining a non indexed table

I tried looking for a similar example to my problem but could not reproduce the solution to my success.
I have 2 tables, Controller and Actions.
The Actions table has the columns Step, Script, Description, Wait_Until and Ref_Code.
The Controller table can only be joined on the Action table by the Ref_Code.
The Action table cannot have a PK because for each Ref_Code there is a Step to be taken.
Im getting an error when trying to update the Controller table using a merge statement:
ORA-30926: unable to get a stable set of rows in the source tables
My merge statement is as follows:
MERGE INTO DSTETL.SHB_FTPS_CONTROLLER ftpsc
USING (SELECT DISTINCT FTPSC.SESSION_ID,
FTPSC.ORDER_DATE,
sa.step,
sa.next_step,
LAST_ACTION_TMSTMP,
SA.ACTION_SCRIPT,
sa.ref_code,
SA.WAIT_UNTIL
FROM DSTETL.SHB_FTPS_CONTROLLER ftpsc, DSTETL.SHB_ACTIONS sa
WHERE SA.REF_CODE = FTPSC.REF_CODE
AND SA.STEP > ftpsc.curr_step
AND sa.step = ftpsc.next_step) v1
ON (v1.REF_CODE = FTPSC.REF_CODE)
WHEN MATCHED
THEN
UPDATE SET FTPSC.LAST_ACTION_TMSTMP = CURRENT_TIMESTAMP,
ftpsc.next_step = v1.next_step,
ftpsc.curr_step = v1.STEP,
ftpsc.action_script = v1.action_script
WHERE CURRENT_TIMESTAMP >= v1.LAST_ACTION_TMSTMP + v1.WAIT_UNTIL;
COMMIT;
I tried doing this using a normal update as well but Im getting ORA-01732: data manipulation operation not legal on this view.
UPDATE (SELECT FTPSC.SESSION_ID,
FTPSC.ORDER_DATE,
FTPSC.CURR_STEP,
FTPSC.NEXT_STEP,
FTPSC.ACTION_SCRIPT,
sa.step, --New Step
sa.next_step AS "NNS", --New Next Step
FTPSC.LAST_ACTION_TMSTMP,
SA.ACTION_SCRIPT AS "NAS", --New action script
sa.ref_code,
SA.WAIT_UNTIL
FROM DSTETL.SHB_FTPS_CONTROLLER ftpsc
LEFT JOIN
DSTETL.SHB_ACTIONS sa
ON SA.REF_CODE = FTPSC.REF_CODE
AND SA.STEP > ftpsc.curr_step
AND sa.step = ftpsc.next_step) t
SET t.curr_step = t.step,
t.LAST_ACTION_TMSTMP = CURRENT_TIMESTAMP,
t.next_step = t."NNS",
t.action_script = t."NAS";
COMMIT;
Any advice would be appreciated, I already understand this is because the Action table has multiple Ref_Codes but REF_CODE||STEP is unique. And the output of:
SELECT DISTINCT FTPSC.SESSION_ID,
FTPSC.ORDER_DATE,
sa.step,
sa.next_step,
LAST_ACTION_TMSTMP,
SA.ACTION_SCRIPT,
sa.ref_code,
SA.WAIT_UNTIL
FROM DSTETL.SHB_FTPS_CONTROLLER ftpsc, DSTETL.SHB_ACTIONS sa
WHERE SA.REF_CODE = FTPSC.REF_CODE
AND SA.STEP > ftpsc.curr_step
AND sa.step = ftpsc.next_step;
Is how I want the Controller table to be updated like.
Thanks in advance.
It sounds like what you want to do is: update each row in the Controller table with the matching "next step" details from the Actions table. But your Merge statement is querying the Controller table twice, which confuses things.
Is this what you're trying to do?
MERGE INTO DSTETL.SHB_FTPS_CONTROLLER ftpsc
USING (SELECT
step,
next_step,
ACTION_SCRIPT,
ref_code,
WAIT_UNTIL
FROM DSTETL.SHB_ACTIONS
) sa
ON (sa.REF_CODE = FTPSC.REF_CODE)
WHEN MATCHED
THEN
UPDATE SET FTPSC.LAST_ACTION_TMSTMP = CURRENT_TIMESTAMP,
ftpsc.next_step = sa.next_step,
ftpsc.curr_step = sa.STEP,
ftpsc.action_script = sa.action_script
WHERE CURRENT_TIMESTAMP >= ftpsc.LAST_ACTION_TMSTMP + sa.WAIT_UNTIL
AND SA.STEP > ftpsc.curr_step
AND sa.step = ftpsc.next_step;
EDIT: updated query
EDIT2: So, in your original query, in the USING section you were selecting the rows in the Controller table that you wanted to update... but you never joined those rows to the Controller table from the MERGE INTO section to match them up. Having the same alias "ftpsc" just made it less clear that they're two separate objects in the query, and which one you wanted to update.
Honestly I don't really understand why Oracle won't let you update columns that appear in the USING..ON clause. It apparently works fine in SQL Server.

Update statement with joins in Oracle

I need to update one column in table A with the result of a multiplication of one field from table A with one field from table B.
It would be pretty simple to do this in T-SQL, but I can't write the correct syntax in Oracle.
What I've tried:
UPDATE TABLE_A
SET TABLE_A.COLUMN_TO_UPDATE =
(select TABLE_A.COLUMN_WITH_SOME_VALUE * TABLE_B.COLUMN_WITH_PERCENTAGE
from TABLE_A
INNER JOIN TABLE_B
ON TABLE_A.PRODUCT_ID = TABLE_B.PRODUCT_ID
AND TABLE_A.SALES_CHANNEL_ID = TABLE_B.SALES_CHANNEL_ID)
WHERE TABLE_A.MONTH_ID IN (201601, 201602, 201603);
But I keep getting errors. Could anybody help me, please?
I generally prefer to use the below format for such cases since this will ensure there's no update performed if there's no data in the table(query extracted temp table) whereas in the above solution provided by Brian Leach will update the new value as null if there's no record present in the 2nd table but exists in the first table.
UPDATE
(
select TABLE_A.COLUMN_TO_UPDATE
, TABLE_A.PRODUCT_ID
, TABLE_A.COLUMN_WITH_SOME_VALUE * TABLE_B.COLUMN_WITH_PERCENTAGE as value
from TABLE_A
INNER JOIN TABLE_B
ON TABLE_A.PRODUCT_ID = TABLE_B.PRODUCT_ID
AND TABLE_A.SALES_CHANNEL_ID = TABLE_B.SALES_CHANNEL_ID
AND TABLE_A.MONTH_ID IN (201601, 201602, 201603)
) DATA
SET DATA.COLUMN_TO_UPDATE = DATA.value;
This solution can cause key preserved value issues which shouldn't be an issue here since i expect a single row in both the tables for one product(ID).
More on Key Preserved table concept in inner join can be found here
https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:548422757486
#Jayesh Mulwani raiesed a valid point, this will set the value to null if there is no matching record. This may or may not be the desired result. If it isn't, and no change is desirect, you can change the select statement to:
coalesce((SELECT table_b.column_with_percentage
FROM table_b
WHERE table_a.product_id = table_b.product_id AND table_a.sales_channel_id = table_b.sales_channel_id),1)
If this is the desired outcome, Jayesh's solution will be more efficient as it will only update matching records.
UPDATE table_a
SET table_a.column_to_update = table_a.column_with_some_value
* (SELECT table_b.column_with_percentage
FROM table_b
WHERE table_a.product_id = table_b.product_id
AND table_a.sales_channel_id = table_b.sales_channel_id)
WHERE table_a.month_id IN (201601, 201602, 201603);

Update a column based on column from another table

Why does my update statement say - "cannot insert null into gitb_auto_debit_upload.status". The second query returned a record where the column process_status was having 'P' as its value.
Update gitb_auto_debit_upload a
set status = (select nvl(process_status,'O') from gitb_daily_log b
where b.interface_code = 'PHP661OW'
and b. process_ref_no = '4708'
and a.refno = b.external_ref_no
and a.recordno = b. seq_no
) ;
select * from gitb_auto_debit_upload a, gitb_daily_log b where b.interface_code = 'PHP661OW'
and b. process_ref_no = '4708'
and a.refno = b.external_ref_no
and a. recordno = b. seq_no
The error message comes from a record in gitb_auto_debit_upload for which the select (the one inside the update) statement returns no row.
Your update statement processes all records of gitb_auto_debit_upload.
Your select (the one you use to test the status value) statement only those records for which a record in gitb_daily_log exists.
You need to change the update statement to either only update those rows for whicht the select return a row or to place the NVL() around the select.

Resources