Home » SQL & PL/SQL » SQL & PL/SQL » PL/SQL for Insert/Update
| PL/SQL for Insert/Update [message #633181] |
Thu, 12 February 2015 01:42  |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
Hi.
My PL/SQL code is this
CREATE OR REPLACE procedure P_S13018_TEST as
--===================================================================================--
/*
Thursday, 12 February, 2015 11:51:42 AM - Sim Chun Seng method
*/
TYPE tbl IS TABLE OF CSM_DAILY_CKC%ROWTYPE;
src tbl;
row_update number(10):=0;
row_insert number(10):=0;
row_reject number(10):=0;
i number:=0;
j number:=0;
v_ErrorCode number;
v_Errortext varchar2(200);
start_time date := sysdate;
proc_name VARCHAR2(36) := 'P_S13018_TEST';
table_name VARCHAR2(36) := 'S13018_CSM_DAILY_CKC';
subject_area VARCHAR2(45) := 'CSM-CKC Daily Report';
begin
select * BULK COLLECT into src
from CSM_DAILY_CKC where system_date='13/12/2014';
FOR i IN src.first .. src.last LOOP
UPDATE S13018_CSM_DAILY_CKC SET
CKC_ID = src(i).CKC_ID,
SR_NUM = src(i).SR_NUM,
TR_NUM = src(i).TR_NUM,
CKC_STATUS = src(i).CKC_STATUS,
CKC_CREATED_DATE = src(i).CKC_CREATED_DATE,
SYSTEM_DATE = src(i).SYSTEM_DATE,
AGING = src(i).AGING,
CUSTOMER_NAME = src(i).CUSTOMER_NAME,
SERVICE_NUM = src(i).SERVICE_NUM,
LOGIN_ID = src(i).LOGIN_ID,
SIEBEL_CUST_ID = src(i).SIEBEL_CUST_ID,
PRIMARY_CONTACT = src(i).PRIMARY_CONTACT,
MAIN_CONTACT_MOBILE = src(i).MAIN_CONTACT_MOBILE,
MAIN_CONTACT_HOME = src(i).MAIN_CONTACT_HOME,
MAIN_CONTACT_OFFICE = src(i).MAIN_CONTACT_OFFICE,
MAIN_CONTACT_OFFICE_EXT = src(i).MAIN_CONTACT_OFFICE_EXT,
BUILDING_ID = src(i).BUILDING_ID,
CABINET_ID = src(i).CABINET_ID,
DP_ID = src(i).DP_ID,
DSLAM_ID = src(i).DSLAM_ID,
DSLAM_CARD_SLOT = src(i).DSLAM_CARD_SLOT,
CABLE_ID = src(i).CABLE_ID,
DLC_CARD_SLOT = src(i).DLC_CARD_SLOT,
VBBS_CODE = src(i).VBBS_CODE,
ZONE_NAME = src(i).ZONE_NAME,
STATE = src(i).STATE,
CKC_DIAGNOSIS_CODE = src(i).CKC_DIAGNOSIS_CODE,
CKC_OWNER_POSITION = src(i).CKC_OWNER_POSITION,
CKC_CREATOR_GROUP = src(i).CKC_CREATOR_GROUP,
CKC_CREATOR_POSITION = src(i).CKC_CREATOR_POSITION,
MANUFACTURER_NUM = src(i).MANUFACTURER_NUM,
LEVEL_IND = src(i).LEVEL_IND
WHERE
CKC_ID = src(i).CKC_ID and
SIEBEL_CUST_ID = src(i).SIEBEL_CUST_ID and
CUSTOMER_NAME = src(i).CUSTOMER_NAME and
SERVICE_NUM = src(i).SERVICE_NUM
;
row_update := row_update+1;
IF SQL%ROWCOUNT = 0 THEN
INSERT INTO S13018_CSM_DAILY_CKC (
CKC_ID, SR_NUM, TR_NUM, CKC_STATUS, CKC_CREATED_DATE, SYSTEM_DATE, AGING, CUSTOMER_NAME, SERVICE_NUM, LOGIN_ID, SIEBEL_CUST_ID,
PRIMARY_CONTACT, MAIN_CONTACT_MOBILE, MAIN_CONTACT_HOME, MAIN_CONTACT_OFFICE, MAIN_CONTACT_OFFICE_EXT, BUILDING_ID, CABINET_ID,
DP_ID, DSLAM_ID, DSLAM_CARD_SLOT, CABLE_ID, DLC_CARD_SLOT, VBBS_CODE, ZONE_NAME, STATE, CKC_DIAGNOSIS_CODE, CKC_OWNER_POSITION,
CKC_CREATOR_GROUP, CKC_CREATOR_POSITION, MANUFACTURER_NUM, LEVEL_IND
)
VALUES (
src(i).CKC_ID, src(i).SR_NUM, src(i).TR_NUM, src(i).CKC_STATUS, src(i).CKC_CREATED_DATE, src(i).SYSTEM_DATE, src(i).AGING,
src(i).CUSTOMER_NAME, src(i).SERVICE_NUM, src(i).LOGIN_ID, src(i).SIEBEL_CUST_ID, src(i).PRIMARY_CONTACT,
src(i).MAIN_CONTACT_MOBILE, src(i).MAIN_CONTACT_HOME, src(i).MAIN_CONTACT_OFFICE, src(i).MAIN_CONTACT_OFFICE_EXT,
src(i).BUILDING_ID, src(i).CABINET_ID, src(i).DP_ID, src(i).DSLAM_ID, src(i).DSLAM_CARD_SLOT, src(i).CABLE_ID, src(i).DLC_CARD_SLOT,
src(i).VBBS_CODE, src(i).ZONE_NAME, src(i).STATE, src(i).CKC_DIAGNOSIS_CODE, src(i).CKC_OWNER_POSITION, src(i).CKC_CREATOR_GROUP,
src(i).CKC_CREATOR_POSITION, src(i).MANUFACTURER_NUM, src(i).LEVEL_IND
);
row_insert := row_insert +1;
END IF;
END LOOP;
-- LOG ERRORS INTO ('daily_load') REJECT LIMIT 25;
commit;
dbms_output.put_line(chr(0));
dbms_output.put_line(chr(10));
dbms_output.put_line('UPDATE for '||table_name);
dbms_output.put_line('-------------------------------------------------');
dbms_output.put_line(chr(0));
DBMS_OUTPUT.PUT_LINE (row_update ||' rows have been updated!');
DBMS_OUTPUT.PUT_LINE (row_insert ||' rows have been inserted!');
DBMS_OUTPUT.PUT_LINE (row_reject ||' rows have been rejected!');
DBMS_OUTPUT.PUT_LINE('error_code:'||v_ErrorCode);
DBMS_OUTPUT.PUT_LINE('error_msg:'||v_ErrorText);
dbms_output.put_line(chr(0));
insert into PROCEDURE_TRACKING_LOG
(procedure_name, table_name, rows_inserted, rows_updated, rows_deleted, rows_inserted_of_deletion, rows_inserted_after_deletion,
rows_rejected, start_time, end_time, elapse_time, remarks, subject_area)
values
(proc_name,
table_name,row_insert,row_update,NULL,NULL,NULL,row_reject,start_time,sysdate,(sysdate-start_time)* 86400,
v_ErrorText,subject_area);
commit;
END;
/
My question is how do I capture the rows_updated and rows_inserted correctly?
It seems that the row_update give the total count of the source table.
Thank you.
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633188 is a reply to message #633184] |
Thu, 12 February 2015 02:16   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
Michel Cadot wrote on Thu, 12 February 2015 15:58
Row by row is slow by slow.
Change the whole code.
Thanks for your feedback.
But what do you actually mean?
By the way, I used to use this method, but one of my colleague says this..
dwh job should be performed in bulks rather than row by row.
example below is many times simpler and standard...
BEGIN
INSERT INTO s53449.test1
SELECT account_num
FROM tel_profile
WHERE rownum < 100
LOG ERRORS INTO s53449.err ('daily_load') REJECT LIMIT 25;
commit;
DBMS_OUTPUT.PUT_LINE('record inserted: ' || TO_CHAR(SQL%ROWCOUNT));
END;
/
My common code:
CREATE OR REPLACE procedure P_S13018_TEST as
--===================================================================================--
cursor A is
select* from CSM_DAILY_CKC where system_date='13/12/2014';
arec A%rowtype;
row_update number(10):=0;
row_insert number(10):=0;
row_reject number(10):=0;
i number:=0;
j number:=0;
v_ErrorCode number;
v_Errortext varchar2(200);
start_time date := sysdate;
proc_name VARCHAR2(36) := 'P_S13018_TEST';
table_name VARCHAR2(36) := 'S13018_CSM_DAILY_CKC';
subject_area VARCHAR2(45) := 'CSM-CKC Daily Report';
begin
OPEN A;
loop
FETCH A INTO arec;
exit when A%notfound;
BEGIN
UPDATE S13018_CSM_DAILY_CKC SET
CKC_ID = arec.CKC_ID,
SR_NUM = arec.SR_NUM,
TR_NUM = arec.TR_NUM,
CKC_STATUS = arec.CKC_STATUS,
CKC_CREATED_DATE = arec.CKC_CREATED_DATE,
SYSTEM_DATE = arec.SYSTEM_DATE,
AGING = arec.AGING,
CUSTOMER_NAME = arec.CUSTOMER_NAME,
SERVICE_NUM = arec.SERVICE_NUM,
LOGIN_ID = arec.LOGIN_ID,
SIEBEL_CUST_ID = arec.SIEBEL_CUST_ID,
PRIMARY_CONTACT = arec.PRIMARY_CONTACT,
MAIN_CONTACT_MOBILE = arec.MAIN_CONTACT_MOBILE,
MAIN_CONTACT_HOME = arec.MAIN_CONTACT_HOME,
MAIN_CONTACT_OFFICE = arec.MAIN_CONTACT_OFFICE,
MAIN_CONTACT_OFFICE_EXT = arec.MAIN_CONTACT_OFFICE_EXT,
BUILDING_ID = arec.BUILDING_ID,
CABINET_ID = arec.CABINET_ID,
DP_ID = arec.DP_ID,
DSLAM_ID = arec.DSLAM_ID,
DSLAM_CARD_SLOT = arec.DSLAM_CARD_SLOT,
CABLE_ID = arec.CABLE_ID,
DLC_CARD_SLOT = arec.DLC_CARD_SLOT,
VBBS_CODE = arec.VBBS_CODE,
ZONE_NAME = arec.ZONE_NAME,
STATE = arec.STATE,
CKC_DIAGNOSIS_CODE = arec.CKC_DIAGNOSIS_CODE,
CKC_OWNER_POSITION = arec.CKC_OWNER_POSITION,
CKC_CREATOR_GROUP = arec.CKC_CREATOR_GROUP,
CKC_CREATOR_POSITION = arec.CKC_CREATOR_POSITION,
MANUFACTURER_NUM = arec.MANUFACTURER_NUM,
LEVEL_IND = arec.LEVEL_IND
WHERE
CKC_ID = arec.CKC_ID and
SIEBEL_CUST_ID = arec.SIEBEL_CUST_ID and
CUSTOMER_NAME = arec.CUSTOMER_NAME and
SERVICE_NUM = arec.SERVICE_NUM
;
IF SQL%FOUND then
row_update := row_update+1;
else
INSERT INTO CSM_DAILY_CKC
(CKC_ID, SR_NUM, TR_NUM, CKC_STATUS, CKC_CREATED_DATE, SYSTEM_DATE, AGING, CUSTOMER_NAME, SERVICE_NUM, LOGIN_ID, SIEBEL_CUST_ID,
PRIMARY_CONTACT, MAIN_CONTACT_MOBILE, MAIN_CONTACT_HOME, MAIN_CONTACT_OFFICE, MAIN_CONTACT_OFFICE_EXT, BUILDING_ID, CABINET_ID,
DP_ID, DSLAM_ID, DSLAM_CARD_SLOT, CABLE_ID, DLC_CARD_SLOT, VBBS_CODE, ZONE_NAME, STATE)
VALUES
(arec.CKC_ID, arec.SR_NUM, arec.TR_NUM, arec.CKC_STATUS, arec.CKC_CREATED_DATE, arec.SYSTEM_DATE, arec.AGING, arec.CUSTOMER_NAME,
arec.SERVICE_NUM, arec.LOGIN_ID, arec.SIEBEL_CUST_ID, arec.PRIMARY_CONTACT, arec.MAIN_CONTACT_MOBILE, arec.MAIN_CONTACT_HOME,
arec.MAIN_CONTACT_OFFICE, arec.MAIN_CONTACT_OFFICE_EXT, arec.BUILDING_ID, arec.CABINET_ID, arec.DP_ID, arec.DSLAM_ID,
arec.DSLAM_CARD_SLOT, arec.CABLE_ID, arec.DLC_CARD_SLOT, arec.VBBS_CODE, arec.ZONE_NAME, arec.STATE)
;
row_insert := row_insert +1;
i := i + 1;
if i > 500 then
commit;
i := 0;
end if;
END IF;
exception when others then
row_reject:=row_reject+1;
v_ErrorCode :=SQLCODE;
v_ErrorText :=SUBSTR(SQLERRM,1,200);
end;
i := i + 1;
if i > 500 then
commit;
i := 0;
end if;
END LOOP;
close A;
dbms_output.put_line(chr(0));
dbms_output.put_line(chr(10));
dbms_output.put_line('UPDATE for '||table_name);
dbms_output.put_line('-------------------------------------------------');
dbms_output.put_line(chr(0));
DBMS_OUTPUT.PUT_LINE (row_update ||' rows have been updated!');
DBMS_OUTPUT.PUT_LINE (row_insert ||' rows have been inserted!');
DBMS_OUTPUT.PUT_LINE (row_reject ||' rows have been rejected!');
DBMS_OUTPUT.PUT_LINE('error_code:'||v_ErrorCode);
DBMS_OUTPUT.PUT_LINE('error_msg:'||v_ErrorText);
dbms_output.put_line(chr(0));
insert into PROCEDURE_TRACKING_LOG
(procedure_name, table_name, rows_inserted, rows_updated, rows_deleted, rows_inserted_of_deletion, rows_inserted_after_deletion,
rows_rejected, start_time, end_time, elapse_time, remarks, subject_area)
values
(proc_name,
table_name,row_insert,row_update,NULL,NULL,NULL,row_reject,start_time,sysdate,(sysdate-start_time)* 86400,
v_ErrorText,subject_area);
commit;
END;
/
|
|
|
|
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633192 is a reply to message #633190] |
Thu, 12 February 2015 02:38   |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
aimy wrote on Thu, 12 February 2015 13:59Why it is wrong?
It's actually not wrong, but inefficient.
Oracle uses two engines to process PL/SQL code. PL/SQL code is handled by the PL/SQL engine while all SQL is handled by the SQL engine. There is an overhead associated with each context switch between the two engines. If PL/SQL code loops through a collection performing the same DML operation for each item in the collection it is possible to reduce context switches by bulk binding the whole collection to the DML statement in one operation. Read this nice article by Tim. Do the test yourself and understand.
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633193 is a reply to message #633191] |
Thu, 12 February 2015 02:39   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
Michel Cadot wrote on Thu, 12 February 2015 16:36
Row by row (for loop) is slow by slow.
Use BULK operation as your colleague told you.
Is it the same as BULK COLLECT in the first post?
If I use this method..
BEGIN
INSERT INTO s53449.test1
SELECT account_num
FROM tel_profile
WHERE rownum < 100
LOG ERRORS INTO s53449.err ('daily_load') REJECT LIMIT 25;
commit;
DBMS_OUTPUT.PUT_LINE('record inserted: ' || TO_CHAR(SQL%ROWCOUNT));
END;
/
What should be the code if I want to do the update as well?
Thank you.
|
|
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633197 is a reply to message #633194] |
Thu, 12 February 2015 02:51   |
cookiemonster
Messages: 13975 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
The most efficient way to do it isn't listed in the article - use MERGE
As for why you're update count in the original code is wrong - you're incrementing it before checking if the update did anything.
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633244 is a reply to message #633197] |
Thu, 12 February 2015 22:13   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
cookiemonster wrote on Thu, 12 February 2015 16:51The most efficient way to do it isn't listed in the article - use MERGE
As for why you're update count in the original code is wrong - you're incrementing it before checking if the update did anything.
Thanks for your suggestion.
So I come out with this. Is it OK? It used external package named ETL though.
CREATE OR REPLACE procedure P_S13018_TEST (param varchar2) as
--===================================================================================--
/*
Thursday, 12 February, 2015 11:51:42 AM - Sim Chun Seng method
*/
row_update number(10):=0;
row_insert number(10):=0;
row_reject number(10):=0;
i number:=0;
j number:=0;
v_ErrorCode number;
v_Errortext varchar2(200);
start_time date := sysdate;
proc_name VARCHAR2(36) := 'P_S13018_TEST';
table_name VARCHAR2(36) := 'S13018_CSM_DAILY_CKC';
subject_area VARCHAR2(45) := 'CSM-CKC Daily Report';
custom_text VARCHAR2(36) := param;
begin
etl.reset_counters;
MERGE INTO S13018_CSM_DAILY_CKC tgt
USING (select * from S13018_CSM_DAILY_bkp where ckc_status=param) SRC
ON (tgt.CKC_ID = src.CKC_ID and
tgt.SIEBEL_CUST_ID = src.SIEBEL_CUST_ID and
tgt.CKC_CREATED_DATE = src.CKC_CREATED_DATE and
tgt.SERVICE_NUM = src.SERVICE_NUM)
/* update the data */
WHEN MATCHED THEN
UPDATE
SET
SR_NUM = CASE ETL.MERGE_COUNTER(ETL.C_UPDATING) when 0 then SRC.sr_num END,
TR_NUM = src.TR_NUM,
CKC_STATUS = src.CKC_STATUS,
SYSTEM_DATE = src.SYSTEM_DATE,
AGING = src.AGING,
CUSTOMER_NAME = src.CUSTOMER_NAME,
LOGIN_ID = src.LOGIN_ID,
PRIMARY_CONTACT = src.PRIMARY_CONTACT,
MAIN_CONTACT_MOBILE = src.MAIN_CONTACT_MOBILE,
MAIN_CONTACT_HOME = src.MAIN_CONTACT_HOME,
MAIN_CONTACT_OFFICE = src.MAIN_CONTACT_OFFICE,
MAIN_CONTACT_OFFICE_EXT = src.MAIN_CONTACT_OFFICE_EXT,
BUILDING_ID = src.BUILDING_ID,
CABINET_ID = src.CABINET_ID,
DP_ID = src.DP_ID,
DSLAM_ID = src.DSLAM_ID,
DSLAM_CARD_SLOT = src.DSLAM_CARD_SLOT,
CABLE_ID = src.CABLE_ID,
DLC_CARD_SLOT = src.DLC_CARD_SLOT,
VBBS_CODE = src.VBBS_CODE,
ZONE_NAME = src.ZONE_NAME,
STATE = src.STATE,
CKC_DIAGNOSIS_CODE = src.CKC_DIAGNOSIS_CODE,
CKC_OWNER_POSITION = src.CKC_OWNER_POSITION,
CKC_CREATOR_GROUP = src.CKC_CREATOR_GROUP,
CKC_CREATOR_POSITION = src.CKC_CREATOR_POSITION,
MANUFACTURER_NUM = src.MANUFACTURER_NUM,
LEVEL_IND = src.LEVEL_IND,
timestamp = sysdate
WHEN NOT MATCHED THEN
INSERT (
CKC_ID, SR_NUM, TR_NUM, CKC_STATUS, CKC_CREATED_DATE, SYSTEM_DATE, AGING, CUSTOMER_NAME, SERVICE_NUM, LOGIN_ID, SIEBEL_CUST_ID,
PRIMARY_CONTACT, MAIN_CONTACT_MOBILE, MAIN_CONTACT_HOME, MAIN_CONTACT_OFFICE, MAIN_CONTACT_OFFICE_EXT, BUILDING_ID, CABINET_ID,
DP_ID, DSLAM_ID, DSLAM_CARD_SLOT, CABLE_ID, DLC_CARD_SLOT, VBBS_CODE, ZONE_NAME, STATE, CKC_DIAGNOSIS_CODE, CKC_OWNER_POSITION,
CKC_CREATOR_GROUP, CKC_CREATOR_POSITION, MANUFACTURER_NUM, LEVEL_IND
)
VALUES (
CASE ETL.MERGE_COUNTER(ETL.c_inserting) when 0 then SRC.ckc_id END, src.SR_NUM, src.TR_NUM, src.CKC_STATUS, src.CKC_CREATED_DATE, src.SYSTEM_DATE, src.AGING,
src.CUSTOMER_NAME, src.SERVICE_NUM, src.LOGIN_ID, src.SIEBEL_CUST_ID, src.PRIMARY_CONTACT,
src.MAIN_CONTACT_MOBILE, src.MAIN_CONTACT_HOME, src.MAIN_CONTACT_OFFICE, src.MAIN_CONTACT_OFFICE_EXT,
src.BUILDING_ID, src.CABINET_ID, src.DP_ID, src.DSLAM_ID, src.DSLAM_CARD_SLOT, src.CABLE_ID, src.DLC_CARD_SLOT,
src.VBBS_CODE, src.ZONE_NAME, src.STATE, src.CKC_DIAGNOSIS_CODE, src.CKC_OWNER_POSITION, src.CKC_CREATOR_GROUP,
src.CKC_CREATOR_POSITION, src.MANUFACTURER_NUM, src.LEVEL_IND
);
row_insert:=etl.get_merge_insert_count;
row_update:=etl.get_merge_update_count(sql%rowcount);
commit;
insert into PROCEDURE_TRACKING_LOG
(procedure_name, table_name, rows_inserted, rows_updated, rows_deleted, rows_inserted_of_deletion, rows_inserted_after_deletion,
rows_rejected, start_time, end_time, elapse_time, remarks, subject_area)
values
(proc_name||replace(decode(custom_text,null,null,' ('||custom_text||')'),' ()'),
table_name,row_insert,row_update,NULL,NULL,NULL,row_reject,start_time,sysdate,(sysdate-start_time)* 86400,
v_ErrorText,subject_area);
commit;
dbms_output.put_line(chr(0));
dbms_output.put_line(chr(10));
dbms_output.put_line('UPDATE for '||table_name);
dbms_output.put_line('-------------------------------------------------');
dbms_output.put_line(chr(0));
DBMS_OUTPUT.PUT_LINE (row_update ||' rows have been updated!');
DBMS_OUTPUT.PUT_LINE (row_insert ||' rows have been inserted!');
DBMS_OUTPUT.PUT_LINE (row_reject ||' rows have been rejected!');
DBMS_OUTPUT.PUT_LINE('error_code:'||v_ErrorCode);
DBMS_OUTPUT.PUT_LINE('error_msg:'||v_ErrorText);
dbms_output.put_line(chr(0));
exception when others then
row_reject:=sql%bulk_exceptions.count;
v_ErrorCode :=SQLCODE;
v_ErrorText :=SUBSTR(SQLERRM,1,200);
-- LOG ERRORS INTO ('daily_load') REJECT LIMIT 25;
commit;
END;
/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633548 is a reply to message #633181] |
Sat, 21 February 2015 01:49   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
This is the ETL package content..
CREATE OR REPLACE PACKAGE CRISPBATCH.ETL AS
c_inserting CONSTANT PLS_INTEGER := 0;
c_updating CONSTANT PLS_INTEGER := 1;
FUNCTION merge_counter (
action_in IN PLS_INTEGER DEFAULT c_inserting
) RETURN PLS_INTEGER;
FUNCTION get_merge_update_count RETURN PLS_INTEGER;
FUNCTION get_merge_update_count (
merge_count_in IN PLS_INTEGER
) RETURN PLS_INTEGER;
FUNCTION get_merge_insert_count RETURN PLS_INTEGER;
FUNCTION get_merge_insert_count (
merge_count_in in PLS_INTEGER
) RETURN PLS_INTEGER;
PROCEDURE reset_counters;
END etl;
/
CREATE OR REPLACE PACKAGE BODY CRISPBATCH.ETL AS
g_update_counter PLS_INTEGER NOT NULL := 0;
g_insert_counter PLS_INTEGER NOT NULL := 0;
/*-------------- START OF FUNCTION merge_counter --------------------*/
FUNCTION merge_counter (
action_in IN PLS_INTEGER DEFAULT c_inserting
) RETURN PLS_INTEGER IS
BEGIN
CASE action_in
WHEN c_updating
THEN g_update_counter := g_update_counter + 1;
WHEN c_inserting
THEN g_insert_counter := g_insert_counter + 1;
ELSE
RAISE PROGRAM_ERROR;
END CASE;
RETURN 0;
END merge_counter;
/*----------- START OF FUNCTION get_merge_update_count V1 ---------------*/
FUNCTION get_merge_update_count
RETURN PLS_INTEGER is
BEGIN
RETURN g_update_counter;
END get_merge_update_count;
/*----------- START OF FUNCTION get_merge_update_count V2 ---------------*/
FUNCTION get_merge_update_count (
merge_count_in IN PLS_INTEGER
) RETURN PLS_INTEGER IS
BEGIN
RETURN NVL( merge_count_in - g_insert_counter, 0 );
END get_merge_update_count;
/*----------- START OF FUNCTION get_merge_insert_count V1 ---------------*/
FUNCTION get_merge_insert_count
RETURN PLS_INTEGER IS
BEGIN
RETURN g_insert_counter;
END get_merge_insert_count;
/*----------- START OF FUNCTION get_merge_insert_count V2 ---------------*/
FUNCTION get_merge_insert_count (
merge_count_in IN PLS_INTEGER
) RETURN PLS_INTEGER IS
BEGIN
RETURN NVL( merge_count_in - g_update_counter, 0 );
END get_merge_insert_count;
/*-------------- START OF FUNCTION reset_counters --------------------*/
PROCEDURE reset_counters IS
BEGIN
g_update_counter := 0;
g_insert_counter := 0;
END reset_counters;
END etl;
/
I need to track the number of inserted/updated records for tracking purposes in case the figure is not tally with source or something like that.
Thank you.
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633550 is a reply to message #633548] |
Sat, 21 February 2015 02:06   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
But now I am getting a mysterious error of "ORA-12899: value too large for column "CRISPADM"."CAMS_JDIARY_JURISAGENCY"."D_TEXT" (actual: 4009, maximum: 4000)" whereas when I desc the table source SQL> desc JURISAGENCY.JDIARY@crisp_cams, it is clearly showing D_TEXT VARCHAR2(4000) even the current one.
Do you guys have any idea on this?
Thank you.
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633552 is a reply to message #633551] |
Sat, 21 February 2015 02:12   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
Michel Cadot wrote on Sat, 21 February 2015 16:10
You just try to store 4009 bytes into a 4000 bytes field.
But how could such 4009 bytes exist in the source table with D_text varchar2(4000) as well?
|
|
|
|
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633560 is a reply to message #633555] |
Sat, 21 February 2015 08:50   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
I mean some other data types that could be equivalent to that varchar2(4000).
Anyway your point of translating character might be useful. Can you show me some example whereby the translated length and the original length display the same data?
Thank you.
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633563 is a reply to message #633561] |
Sat, 21 February 2015 09:01   |
 |
Littlefoot
Messages: 21826 Registered: June 2005 Location: Croatia, Europe
|
Senior Member Account Moderator |
|
|
What if that date string was 11/12/2014? Is TO_DATE enough, or would it be better to use appropriate format mask? Because, what is "11" and what is "12"? Which one is a day, and which one is a month?
P.S. Forgot about the DATE literal which uniquely describes date format, 'YYYY-MM-DD'. It is NOT convenient for me, we use 'DD.MM.YYYY', but I can live with it as I *know* that DATE literal is always the same.
[Updated on: Sat, 21 February 2015 09:58] Report message to a moderator
|
|
|
|
|
|
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633652 is a reply to message #633566] |
Tue, 24 February 2015 00:39   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
Thanks a lot for your precise example.
Based on your sample given, it is proven that these two queries yields 2 different results:
select LENGTHB('é') from dual@crisp_cams; - 1
select LENGTHB('é') from dual; - 3
So, I am planning to use the built-in Oracle function CONVERT to solve this issue.
By the way, where would I get the full list of characters that have this kind of issue?
And what would the character be if it is stored inside the target (AL32UTF8) from source (WE8MSWIN1252)? Would them be truncated to '?'
Thank you.
[Updated on: Tue, 24 February 2015 00:39] Report message to a moderator
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633655 is a reply to message #633652] |
Tue, 24 February 2015 01:22   |
 |
Michel Cadot
Messages: 68776 Registered: March 2007 Location: Saint-Maur, France, https...
|
Senior Member Account Moderator |
|
|
Quote:So, I am planning to use the built-in Oracle function CONVERT to solve this issue.
You can use Oracle TRANSLATE function. For instance for WE8MSWIN1252 and French it is:
TRANSLATE(col,
'ƒŠŒŽšœžŸÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïøðñòóôõöùúûüýÿÞþ',
'fSEZsezYAAAAAAECEEEEIIIIDNOOOOOOUUUUYBaaaaaaeceeeeiiiioonooooouuuuyy')
Quote:By the way, where would I get the full list of characters that have this kind of issue?
These are all the characters with code point >= 128, you can use the ASCII function to get the code point:
SQL> select ascii('é') from dual;
ASCII('é')
----------
130
1 row selected.
And CHR function to get the character from its code point. So you can use a loop like:
SQL> begin
2 for i in 128..255 loop
3 dbms_output.put(chr(i));
4 end loop;
5 dbms_output.new_line;
6 end;
7 /
ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñѪº¿®... (output truncated)
PL/SQL procedure successfully completed.
[Updated on: Tue, 24 February 2015 01:24] Report message to a moderator
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633658 is a reply to message #633655] |
Tue, 24 February 2015 01:36   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
Thanks a lot Michael.
But I'm just curious, is it not OK to do this instead...
SELECT '@#$*%ÄÊÍÓØABCDE' original_text, CONVERT('@#$*%ÄÊÍÓØABCDE', 'WE8MSWIN1252', 'AL32UTF8') modified_text,
lengthb('@#$*%ÄÊÍÓØABCDE') original_length,
lengthb(CONVERT('@#$*%ÄÊÍÓØABCDE', 'WE8MSWIN1252', 'AL32UTF8')) modified_length
from dual;
Thank you.
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633662 is a reply to message #633658] |
Tue, 24 February 2015 02:27   |
 |
Michel Cadot
Messages: 68776 Registered: March 2007 Location: Saint-Maur, France, https...
|
Senior Member Account Moderator |
|
|
Compare (from a couple of French words):
SQL> with
2 data as (
3 select 'ambiguïté séquoia après déjà français' original_text
4 from dual
5 )
6 SELECT original_text,
7 CONVERT(original_text, 'WE8MSWIN1252', 'AL32UTF8') modified_text
8 from data
9 /
ORIGINAL_TEXT MODIFIED_TEXT
---------------------------------------- ----------------------------------------
ambiguïté séquoia après déjà français ambigu¿t¿ s¿quoia apr¿s d¿j¿ fran¿ais
With:
SQL> with
2 data as (
3 select 'ambiguïté séquoia après déjà français' original_text
4 from dual
5 )
6 SELECT original_text,
7 translate(original_text,
8 'ƒŠŒŽšœžŸÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïøðñòóôõöùúûüýÿÞþ',
9 'fSEZsezYAAAAAAECEEEEIIIIDNOOOOOOUUUUYBaaaaaaeceeeeiiiioonooooouuuuyy')
10 modified_text
11 from data
12 /
ORIGINAL_TEXT MODIFIED_TEXT
---------------------------------------- ----------------------------------------
ambiguïté séquoia après déjà français ambiguite sequoia apres deja francais
The former turns to be unreadable when the later is understandable by any French speaking person.
[Updated on: Tue, 24 February 2015 02:35] Report message to a moderator
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633663 is a reply to message #633662] |
Tue, 24 February 2015 02:33   |
aimy
Messages: 225 Registered: June 2006
|
Senior Member |
|
|
Thanks a lot Michael. Precise explanation with examples.
As you might already seen, the reason I asked is because if I have to use translate, I need to convert every single character to the equivalent right? That is what I'm trying to skip.
|
|
|
|
| Re: PL/SQL for Insert/Update [message #633664 is a reply to message #633663] |
Tue, 24 February 2015 02:40   |
 |
Michel Cadot
Messages: 68776 Registered: March 2007 Location: Saint-Maur, France, https...
|
Senior Member Account Moderator |
|
|
Only the characters that are not in 0-127 code points that is at most 128 characters (70 for WE8MSWIN1252) I showed you how to get them and then you have to associate them with a new character, you do this once, it will take less than 10 minutes and the result is a good conversion.
I think it is worth to do it, don't you think?
[Updated on: Tue, 24 February 2015 02:41] Report message to a moderator
|
|
|
|
|
|
Goto Forum:
Current Time: Thu Aug 27 00:39:17 CDT 2026
|