Looping thru merge statement
I have a merge statement, this executes for all the rows when the procedure is executed. Here i would like to include this merge statement as the part of LOOP so that all records will not get updated for a one time.
how can i change this merge statement to include as the part of LOOP here.
the user id should be the key to update the table USERS in merge statement, the same user id is exists in the bulk collect too..
BEGIN
v_sysdate:= pkg_utilities.fn_sysdate(1) ;
o_Error_Text := 'ORA-Error in updating end date in user_status table ';
tname:= 'user_status';
MERGE INTO user_status r1
USING (
SELECT rowid rid , lead(start_period) OVER (PARTITION by user_id
order by start_period)- 1 new_enddate FROM user_status ) r2
ON ( r1.rowid = r2.rid )
WHEN MATCHED THEN
UPDATE SET end_period = new_enddate ;
OPEN generic_cv4
FOR SELECT
user_id,user_status_type_id
FROM user_status
WHERE end_period IS NULL;
LOOP
FETCH generic_cv4 BULK COLLECT INTO
v_user_id_seq,
v_user_status_new
LIMIT p_array_size;
EXIT WHEN v_user_id_seq.COUNT = 0;
IF v_user_id_seq.COUNT > 0 THEN
o_Error_Text := 'ORA-Error in update user_status type id in users table ';
tname:= 'users';
FORALL I IN v_user_id_seq.FIRST..v_user_id_seq.LAST
UPDATE users
SET user_status_type_id = v_user_status_new(i),
last_upd_date = v_sysdate
WHERE user_id = v_user_id_seq(i);
END IF;
COMMIT;
END LOOP;
v_user_id_seq.delete;
v_user_status_new.delete;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error' ||sqlerrm);
DBMS_OUTPUT.PUT_LINE(o_Error_Text);
v_sql_err :=SQLERRM;
ROLLBACK;
pkg_champ_message_log.champ_message_log ('PKG_MIGRATE_V1_NESTED_MEMBER.p_update_member_status', tname, null,'Nested', v_sql_err,'Error',o_Error_Text,O_STATUS);
END;
Now lets talk how can i keep this merge statemnet as the part of the loop. It seems your mind is made up.
Unfortunately, what you're asking makes no sense at all. You can't "loop through a merge statement".
If you don't want to use merge for the entire table at once, the only thing you can do is to break up the table in your USING clause by some sort of range (maybe an account number or whatever). You could then run your code for each range (or even run them in parallel).
The only other option is to not use MERGE at all and duplicate the logic of it within your loop (which is what I said in my first response).
Similar Messages
-
PL/SQL how to loop thru SQL statement?
Hey guys. I have this bit of a complicated problem.
I have a cursor that selects a DISTINCT field called Term and a StudentID.
I am looping thru that cursor.
Inside that loop I have another SQL statement that is pulling all rows from the DB where the Term = the Term and the StudentID= the StudentID from the crusor loop.
My problem is how do I get all the information/rows returned from that SQL statement? I need to loop thru it somehow, but I am not sure how to do it.
If there is a better way to get this done feel free to chime in.
Here is my code.
/* CURSOR*/
CURSOR c_GPAPerTerm IS
SELECT DISTINCT Term, Student_ID FROM course_grades
WHERE STUDENT_ID = p_StudentID;
/* OPEN AND LOOP THRU CURSOR*/
OPEN c_GPAPerTerm;
LOOP
FETCH c_GPAPerTerm INTO v_Terms,v_StudentID;
/* SQL STATEMENT NEED TO LOOP THRU AND GET VALUES FOR EACH ROW*/
SELECT Score
INTO v_Scores
FROM course_grades
WHERE Term = v_Terms and StudentID = v_StudentID;
EXIT WHEN c_GPAPerTerm%NOTFOUND;
END LOOP;
CLOSE c_GPAPerTerm;Ok here's my complete code....it's pretty big though...hope it's not too confusing.
It compiles fine if I take the new cursor out, so the error is somewhere in that cursor.
CREATE OR REPLACE PROCEDURE get_Student_GPA(p_StudentID IN NUMBER) AS
/*VARIABLES*/
v_Terms VARCHAR2(6);
v_Courses VARCHAR2(6);
v_Scores NUMBER;
v_Grade CHAR;
v_GPA NUMBER;
v_ScoresTotal NUMBER :=0;
v_StudentID NUMBER;
/*CURSORS*/
CURSOR c_GetTerms IS
SELECT Term
FROM course_grades
WHERE STUDENT_ID = p_StudentID;
CURSOR c_GetCourseAndGrade IS
SELECT Course_ID, Score FROM course_grades
WHERE STUDENT_ID = p_StudentID;
CURSOR c_GPAPerTerm IS
SELECT DISTINCT Term, Student_ID
FROM course_grades
WHERE STUDENT_ID = p_StudentID;
CURSOR c_GetScores (p_Term VARCHAR2, p_StudentID NUMBER) IS
SELECT Score
FROM course_grades
WHERE Term = p_Term AND StudentID = p_StudentID;
/*FUNCTIONS*/
FUNCTION convert_grade(p_GradeNumber IN NUMBER)
RETURN CHAR IS
BEGIN
/* GET NUMERIC GRADE AND CONVERT TO LETTER */
CASE
WHEN p_GradeNumber < 60 THEN RETURN 'F';
WHEN (p_GradeNumber > 59 AND p_GradeNumber < 70) THEN RETURN 'D';
WHEN (p_GradeNumber > 69 AND p_GradeNumber < 80) THEN RETURN 'C';
WHEN (p_GradeNumber > 79 AND p_GradeNumber < 90) THEN RETURN 'B';
WHEN (p_GradeNumber > 89 AND p_GradeNumber < 101) THEN RETURN 'A';
ELSE RETURN 'Z';
END CASE;
END convert_grade;
FUNCTION calculate_gpa(p_TotalHourPoints IN NUMBER, p_TotalHours IN NUMBER)
RETURN NUMBER IS
/*CREATE VARIABLE TO HOLD GPA*/
v_GPA NUMBER;
BEGIN
/*CALCULATE AND OUTPUT GPA*/
v_GPA := p_TotalHourPoints/p_TotalHours;
RETURN v_GPA;
END calculate_gpa;
FUNCTION calculate_point (p_Grade IN CHAR)
RETURN NUMBER IS
BEGIN
/* GET LETTER GRADE AND CONVERT TO NUMBER */
CASE
WHEN p_Grade = 'A' THEN RETURN 4;
WHEN p_Grade = 'B' THEN RETURN 3;
WHEN p_Grade = 'C' THEN RETURN 2;
WHEN p_Grade = 'D' THEN RETURN 1;
WHEN p_Grade = 'F' THEN RETURN 0;
ELSE RETURN 0;
END CASE;
END calculate_point ;
/****BEGIN MAIN BLOCK********/
BEGIN
DBMS_OUTPUT.PUT_LINE('**********TERMS**********');
OPEN c_GetTerms;
LOOP
FETCH c_GetTerms INTO v_Terms;
DBMS_OUTPUT.PUT_LINE('Term: ' || v_Terms);
EXIT WHEN c_GetTerms%NOTFOUND;
END LOOP;
CLOSE c_GetTerms;
DBMS_OUTPUT.PUT_LINE('**********COURSES AND GRADES**********');
OPEN c_GetCourseAndGrade;
LOOP
FETCH c_GetCourseAndGrade INTO v_Courses, v_Scores;
v_Grade := convert_grade(v_Scores);
DBMS_OUTPUT.PUT_LINE('Course: ' || v_Courses || ' Grade: ' || v_Grade);
EXIT WHEN c_GetCourseAndGrade%NOTFOUND;
END LOOP;
CLOSE c_GetCourseAndGrade;
DBMS_OUTPUT.PUT_LINE('**********GPA PER TERM**********');
OPEN c_GPAPerTerm;
LOOP
FETCH c_GPAPerTerm INTO v_Terms,v_StudentID;
/*NEW CURSOR LOOP WILL GO HERE*/
v_ScoresTotal := v_ScoresTotal + v_Scores;
v_GPA := calculate_gpa(v_ScoresTotal, 3);
v_ScoresTotal :=0;
DBMS_OUTPUT.PUT_LINE('Term: ' || v_Terms || ' GPA: ' || v_GPA);
EXIT WHEN c_GPAPerTerm%NOTFOUND;
END LOOP;
CLOSE c_GPAPerTerm;
END get_Student_GPA;
/ -
i would like to know if it is possible to identify the row that is causing the problem when you use a merge statement in pl/sql. i know if you create a cursor and then loop through the data you can identify the column but what about if i have only a merge that will either insert or update. is it possible to identify which row of data cause the problem? thanks
You can use an Error Logging Table<br>
<br>
Nicolas. -
Question on passing string values to Partition clause in a merge statement
Hello All,
I am using the below code to update specific sub-partition data using oracle merge statements.
I am getting the sub-partition name and passing this as a string to the sub-partition clause.
The Merge statement is failing stating that the specified sub-partition does not exist. But the sub-partition do exists for the table.
We are using Oracle 11gr2 database.
Below is the code which I am using to populate the data.
declare
ln_min_batchkey PLS_INTEGER;
ln_max_batchkey PLS_INTEGER;
lv_partition_name VARCHAR2 (32767);
lv_subpartition_name VARCHAR2 (32767);
begin
FOR m1 IN ( SELECT (year_val + 1) AS year_val, year_val AS orig_year_val
FROM ( SELECT DISTINCT
TO_CHAR (batch_create_dt, 'YYYY') year_val
FROM stores_comm_mob_sub_temp
ORDER BY 1)
ORDER BY year_val)
LOOP
lv_partition_name :=
scmsa_handset_mobility_data_build.fn_get_partition_name (
p_table_name => 'STORES_COMM_MOB_SUB_INFO',
p_search_string => m1.year_val);
FOR m2
IN (SELECT DISTINCT
'M' || TO_CHAR (batch_create_dt, 'MM') AS month_val
FROM stores_comm_mob_sub_temp
WHERE TO_CHAR (batch_create_dt, 'YYYY') = m1.orig_year_val)
LOOP
lv_subpartition_name :=
scmsa_handset_mobility_data_build.fn_get_subpartition_name (
p_table_name => 'STORES_COMM_MOB_SUB_INFO',
p_partition_name => lv_partition_name,
p_search_string => m2.month_val);
DBMS_OUTPUT.PUT_LINE('The lv_subpartition_name => '||lv_subpartition_name||' and lv_partition_name=> '||lv_partition_name);
IF lv_subpartition_name IS NULL
THEN
DBMS_OUTPUT.PUT_LINE('INSIDE IF => '||m2.month_val);
INSERT INTO STORES_COMM_MOB_SUB_INFO T1 (
t1.ntlogin,
t1.first_name,
t1.last_name,
t1.job_title,
t1.store_id,
t1.batch_create_dt)
SELECT t2.ntlogin,
t2.first_name,
t2.last_name,
t2.job_title,
t2.store_id,
t2.batch_create_dt
FROM stores_comm_mob_sub_temp t2
WHERE TO_CHAR (batch_create_dt, 'YYYY') = m1.orig_year_val
AND 'M' || TO_CHAR (batch_create_dt, 'MM') =
m2.month_val;
ELSIF lv_subpartition_name IS NOT NULL
THEN
DBMS_OUTPUT.PUT_LINE('INSIDE ELSIF => '||m2.month_val);
MERGE INTO (SELECT *
FROM stores_comm_mob_sub_info
SUBPARTITION (lv_subpartition_name)) T1
USING (SELECT *
FROM stores_comm_mob_sub_temp
WHERE TO_CHAR (batch_create_dt, 'YYYY') =
m1.orig_year_val
AND 'M' || TO_CHAR (batch_create_dt, 'MM') =
m2.month_val) T2
ON (T1.store_id = T2.store_id
AND T1.ntlogin = T2.ntlogin)
WHEN MATCHED
THEN
UPDATE SET
t1.postpaid_totalqty =
(NVL (t1.postpaid_totalqty, 0)
+ NVL (t2.postpaid_totalqty, 0)),
t1.sales_transaction_dt =
GREATEST (
NVL (t1.sales_transaction_dt,
t2.sales_transaction_dt),
NVL (t2.sales_transaction_dt,
t1.sales_transaction_dt)),
t1.batch_create_dt =
GREATEST (
NVL (t1.batch_create_dt, t2.batch_create_dt),
NVL (t2.batch_create_dt, t1.batch_create_dt))
WHEN NOT MATCHED
THEN
INSERT (t1.ntlogin,
t1.first_name,
t1.last_name,
t1.job_title,
t1.store_id,
t1.batch_create_dt)
VALUES (t2.ntlogin,
t2.first_name,
t2.last_name,
t2.job_title,
t2.store_id,
t2.batch_create_dt);
END IF;
END LOOP;
END LOOP;
COMMIT;
end;
Much appreciate your inputs here.
Thanks,
MK.I've not used partitioning, but I do not see MERGE supporting a variable as a partition name in
MERGE INTO (SELECT *
FROM stores_comm_mob_sub_info
SUBPARTITION (lv_subpartition_name)) T1
USING ... I suspect it is looking for a partition called lv_subpartition_name.
I also don't see why you need that partition name - the ON clause should be able to identify the partition's criteria. -
Issue while using SUBPARTITION clause in the MERGE statement in PLSQL Code
Hello All,
I am using the below code to update specific sub-partition data using oracle merge statements.
I am getting the sub-partition name and passing this as a string to the sub-partition clause.
The Merge statement is failing stating that the specified sub-partition does not exist. But the sub-partition do exists for the table.
We are using Oracle 11gr2 database.
Below is the code which I am using to populate the data.
declare
ln_min_batchkey PLS_INTEGER;
ln_max_batchkey PLS_INTEGER;
lv_partition_name VARCHAR2 (32767);
lv_subpartition_name VARCHAR2 (32767);
begin
FOR m1 IN ( SELECT (year_val + 1) AS year_val, year_val AS orig_year_val
FROM ( SELECT DISTINCT
TO_CHAR (batch_create_dt, 'YYYY') year_val
FROM stores_comm_mob_sub_temp
ORDER BY 1)
ORDER BY year_val)
LOOP
lv_partition_name :=
scmsa_handset_mobility_data_build.fn_get_partition_name (
p_table_name => 'STORES_COMM_MOB_SUB_INFO',
p_search_string => m1.year_val);
FOR m2
IN (SELECT DISTINCT
'M' || TO_CHAR (batch_create_dt, 'MM') AS month_val
FROM stores_comm_mob_sub_temp
WHERE TO_CHAR (batch_create_dt, 'YYYY') = m1.orig_year_val)
LOOP
lv_subpartition_name :=
scmsa_handset_mobility_data_build.fn_get_subpartition_name (
p_table_name => 'STORES_COMM_MOB_SUB_INFO',
p_partition_name => lv_partition_name,
p_search_string => m2.month_val);
DBMS_OUTPUT.PUT_LINE('The lv_subpartition_name => '||lv_subpartition_name||' and lv_partition_name=> '||lv_partition_name);
IF lv_subpartition_name IS NULL
THEN
DBMS_OUTPUT.PUT_LINE('INSIDE IF => '||m2.month_val);
INSERT INTO STORES_COMM_MOB_SUB_INFO T1 (
t1.ntlogin,
t1.first_name,
t1.last_name,
t1.job_title,
t1.store_id,
t1.batch_create_dt)
SELECT t2.ntlogin,
t2.first_name,
t2.last_name,
t2.job_title,
t2.store_id,
t2.batch_create_dt
FROM stores_comm_mob_sub_temp t2
WHERE TO_CHAR (batch_create_dt, 'YYYY') = m1.orig_year_val
AND 'M' || TO_CHAR (batch_create_dt, 'MM') =
m2.month_val;
ELSIF lv_subpartition_name IS NOT NULL
THEN
DBMS_OUTPUT.PUT_LINE('INSIDE ELSIF => '||m2.month_val);
MERGE INTO (SELECT *
FROM stores_comm_mob_sub_info
SUBPARTITION (lv_subpartition_name)) T1 --> Issue Here
USING (SELECT *
FROM stores_comm_mob_sub_temp
WHERE TO_CHAR (batch_create_dt, 'YYYY') =
m1.orig_year_val
AND 'M' || TO_CHAR (batch_create_dt, 'MM') =
m2.month_val) T2
ON (T1.store_id = T2.store_id
AND T1.ntlogin = T2.ntlogin)
WHEN MATCHED
THEN
UPDATE SET
t1.postpaid_totalqty =
(NVL (t1.postpaid_totalqty, 0)
+ NVL (t2.postpaid_totalqty, 0)),
t1.sales_transaction_dt =
GREATEST (
NVL (t1.sales_transaction_dt,
t2.sales_transaction_dt),
NVL (t2.sales_transaction_dt,
t1.sales_transaction_dt)),
t1.batch_create_dt =
GREATEST (
NVL (t1.batch_create_dt, t2.batch_create_dt),
NVL (t2.batch_create_dt, t1.batch_create_dt))
WHEN NOT MATCHED
THEN
INSERT (t1.ntlogin,
t1.first_name,
t1.last_name,
t1.job_title,
t1.store_id,
t1.batch_create_dt)
VALUES (t2.ntlogin,
t2.first_name,
t2.last_name,
t2.job_title,
t2.store_id,
t2.batch_create_dt);
END IF;
END LOOP;
END LOOP;
COMMIT;
end;
Much appreciate your inputs here.
Thanks,
MK.
(SORRY TO POST THE SAME QUESTION TWICE).
Edited by: Maddy on May 23, 2013 10:20 PMDuplicate question
-
Hi all,
I am working on oracle9i
I am using the Merge Statement to INS/UPD rows
I am using loops to
I am updating 29 rows as insert and 1 row a update
Values are inserting and updating correctly in table
But in Sql prompt
I am getting the output as
below
12:03:54 SQL> execute Pr_Bdms_Cont_Insupd;
1 rows merged.
1 rows inserted.
1 rows updated.
PL/SQL procedure successfully completed.
But i take out the loop i am getting exact result
12:03:54 SQL> execute Pr_Bdms_Cont_Insupd;
30 rows merged.
29 rows inserted.
1 rows updated.
PL/SQL procedure successfully completed.
Any help
Below is my procedure
and
CREATE OR REPLACE PROCEDURE Pr_EMP_Insupd IS
empID VARCHAR2(7);
CURSOR C_empno IS SELECT empno FROM TEMP WHERE ROWNUM < 30;
REC_BIN C_empid%ROWTYPE;
BEGIN
FOR REC_BIN IN C_empid LOOP
empID := fn_emp_Id(REC_BIN.Bin);-- Calling function
Merge INTO EMP E
BGC
USING (SELECT A.EMP_ID,B.SALARY,B.BONUS
FROM EMP_IN A, TEMP B
WHERE A.EMPNO = B.EMPNO
AND A.EMP_ID = EMPID)NP
ON(E.EMP_ID = NP.EMP_ID)
WHEN MATCHED THEN UPDATE SET E.SALARY = NP.SALARY,
E.BONUS = NP.BONUS
WHEN NOT MATCHED THEN INSERT (E.EMP_ID,E.SALARY,E.BONUS,E.CREATED_DATE)
VALUES (CASE Check_Upd_Ins.merge_counter(Check_Upd_Ins.c_inserting)
WHEN 0 THEN E.EMP_ID
END,
E.SALARY,E.BONUS,SYSDATE);
END LOOP;
/* Use insert count... using ETL Package*/
dbms_output.put_line(Check_Upd_Ins.get_merge_update_count(SQL%rowcount) || ' rows updated.');
dbms_output.put_line(Check_Upd_Ins.get_merge_insert_count || ' rows inserted.');
Check_Upd_Ins.reset_counters;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20000, SQLERRM(SQLCODE));
END Pr_EMP_Insupd;Perhaps I can help you with this piece of code and this link :
MERGE INTO bonuses D
USING (SELECT employee_id, salary, department_id FROM employees
WHERE department_id = 80) S
ON (D.employee_id = S.employee_id)
WHEN MATCHED THEN UPDATE SET D.bonus = D.bonus + S.salary*.01
WHEN NOT MATCHED THEN INSERT (D.employee_id, D.bonus)
VALUES (S.employee_id, S.salary*0.1);
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96624/13_elems30.htm#37586
Joel P�rez -
Why won't this MERGE statement work?
I am testing out a MERGE statement, which contains a subquery that will return no rows...on this condition, it should insert a record; however I get 0 records merged. Why is this?
Ultimately, the hard-coded values will actually be passed in as parameters. If those a record with those four values is not found, then it should insert.
MERGE INTO tb_slea_election_worksheet A
USING
(SELECT i.slea_year,i.empid,i.bda_sum_sort,i.bda_dtl_sort FROM tb_slea_election_worksheet i
WHERE slea_year = '2008'
AND empid = '6468T'
AND bda_sum_sort = '30'
AND bda_dtl_sort = '9999'
) B
ON (A.slea_year = B.slea_year
AND A.empid =B.empid
AND A.bda_sum_sort = B.bda_sum_sort
AND A.bda_dtl_sort = B.bda_dtl_sort)
WHEN MATCHED THEN
UPDATE SET A.fa_proj_exp_amt = 888
WHEN NOT MATCHED THEN
INSERT (slea_year,empid,bda_sum_sort,bda_dtl_sort,act_exp_lst_yr,fa_proj_exp_amt)
VALUES ( '2008','6468T','30','9999','0','55');A merge statement is just a much more efficient way of doing something like this pl/sql block
DECLARE
l_n NUMBER;
BEGIN
FOR r IN (SELECT pk, col1, col2 FROM source) LOOP
BEGIN
SELECT 1 INTO l_n
FROM target
WHERE pk = r.pk;
UPDATE target
SET col1 = r.col1,
col2 = r.col2
WHERE pk = r.pk;
EXCEPTION WHEN NO_DATA_FOUND THEN
INSERT INTO target
VALUES(r.pk, r.col1, r.col2);
END;
END LOOP;
END;So, if the select from source returns no rows, nothing is going to happen.
John -
Returning clause in MERGE statement
Hi ,
I'm using Oracle 10g Version
I tried the below code using UPDATE with Returning Clause & MERGE with Returning Clause .
I found NO errors while working with UPDATE statement . The following is the code with UPDATE statement
DECLARE
TYPE empno_list IS TABLE OF emp.empno%TYPE;
vempno_list empno_list;
BEGIN
UPDATE emp
SET comm = 11
WHERE deptno IN (SELECT deptno FROM dept)
RETURNING empno
BULK COLLECT INTO vempno_list;
FOR i IN vempno_list.FIRST .. vempno_list.LAST
LOOP
DBMS_OUTPUT.put_line ('Values of EMP ' || vempno_list (i));
END LOOP;
END;
But getting the error PL/SQL: ORA-00933: SQL command not properly ended when working with MERGE Statement
declare
type empno_list is table of emp.empno%type;
vempno_list empno_list;
begin
merge into emp tgt
using dept src
on (src.deptno =tgt.deptno)
when matched then
update set tgt.comm=12
returning tgt.empno bulk collect into vempno_list ;
for i in vempno_list.first .. vempno_list.last loop
dbms_output.put_line('Values of EMP '||vempno_list(i) ) ;
end loop;
end;
Please suggest meProbably because the RETURNING INTO clause doesn't belong to MERGE statement. It's available only for INSERT, UPDATE and DELETE. Here is the quote from Oracle Documentation:
The static RETURNING INTO clause belongs to a DELETE, INSERT, or UPDATE statement. The dynamic RETURNING INTO clause belongs to an EXECUTEIMMEDIATE statement.
And here's the link.
RETURNING INTO Clause
Hope it helps.
Ishan -
hi gems..good afternoon...
My database version is 11.2.0.1.0 64 bit Solaris OS.
I am facing an "ORA-22813: operand value exceeds system limits" while running a procedure.
I have used loggers and found that it is getting failed in a MERGE statement.
That merge statement is used to merge a table with a collection. the code is like below:
MERGE /*+ INDEX(P BALANCE_HISTORIC_INDEX) */
INTO BALANCE_HOLD_HISTORIC P
USING TABLE(GET_BALANCE_HIST(V_MERGE_REC)) M
ON (P.CUSTOMER_ID = M.CUSTOMER_ID AND P.BOOK_ID = M.BOOK_ID AND P.PRODUCT_ID = M.PRODUCT_ID AND P.SUB_BOOK_ID = M.SUB_BOOK_ID AND)
WHEN MATCHED THEN
UPDATE
<set .....>
WHEN NOT MATCHED THEN
INSERT<.....>The parameter of the function GET_BALANCE_HIST(V_MERGE_REC) is a table type.
Now the function GET_BALANCE_HIST(V_MERGE_REC) is a pipelined function and we have used that because the collection V_MERGE_REC may get huge with data.
This proc was running fine from the beginning but from day before yesterday it was continously throwing ORA 22813 error in that line.
please help..thanks in advance..hi paul..thanks for your reply...
the function GET_BALANCE_HIST is not selecting data from any tables.
What this pipeline function is doing is, it is taking the huge collection V_MERGE_REC as parameter and releasing its datas in pipelined form. The code for the functions is :
CREATE OR REPLACE FUNCTION GET_BALANCE_HIST(P_MERGE IN TAB_TYPE_BALANCE_HISTORIC)
RETURN TAB_TYPE_BALANCE_HISTORIC
PIPELINED AS
V_MERGE TAB_TYPE_BALANCE_HISTORIC := TAB_TYPE_BALANCE_HISTORIC();
BEGIN
FOR I IN 1 .. P_MERGE.COUNT LOOP
V_MERGE.EXTEND;
V_MERGE(V_MERGE.LAST) := OBJ_TYPE_BALANCE_HISTORIC(P_MERGE(I).CUSTOMER_ID,
P_MERGE(I).BOOK_ID,
P_MERGE(I).PRODUCT_ID,
P_MERGE(I).SUB_BOOK_ID,
P_MERGE(I).EARNINGS,
P_MERGE(I).EARNINGS_HOUSE,
P_MERGE(I).QUANTITY,
P_MERGE(I).ACCOUNT_INTEGER);
END LOOP;
FOR J IN 1 .. V_MERGE.COUNT LOOP
PIPE ROW(OBJ_TYPE_BALANCE_HISTORIC(V_MERGE(I).CUSTOMER_ID,
V_MERGE(I).BOOK_ID,
V_MERGE(I).PRODUCT_ID,
V_MERGE(I).SUB_BOOK_ID,
V_MERGE(I).EARNINGS,
V_MERGE(I).EARNINGS_HOUSE,
V_MERGE(I).QUANTITY,
V_MERGE(I).ACCOUNT_INTEGER));
END LOOP;
RETURN;
END;I think the error is comming because of the parameter value of V_MERGE_REC. Since it is huge, so loading that into memory is causing problem. But in this case, how can I resolve it?? Can I use a global temporary table for this??
Please suggest... -
The new MERGE statement in Oracle 9i
Has anyone used the new Merge statement to process large amounts of data? Currently we use PL/SQL to update/insert into our tables when we are loading large amounts of data (close to one million rows) because we can set commit points and avoid rollback problems. I am wondering if we use Merge instead how this will affect rollback? Are we still going to have to code for this problem?
Thanks in advance!Thanks for the suggestions. Our problem is that the base table contains 50 million rows and seven indexes, and each month we try to insert/update one million rows. Some of the data in the base table is historical so if we implemented your solution we would lose any records not being updated.
What I am really trying to determine is if the MERGE statement has any redo log ramifications. Will we run in rollback space problems if we implement it instead of running PL/SQL in the following format:
FOR cur_rec in c1 LOOP
UPDATE table a
SET col a = cur_rec.col a, ...
WHERE ...
IF SQL%NOTFOUND THEN
INSERT (col a , col b, col c...)
VALUES (cur_rec.col a, cur_rec.col b...);
END IF;
We commit every 10,000 records (as determined by SQL%ROWCOUNT). This can be time comsuming and Oracle claims that the new MERGE command will avoid costly overhead and reduce data scans. However, I am concerned that we may hit rollback problems if we implement a straight SQL statement such as MERGE. Any thoughts? -
Performance problem with MERGE statement
Version : 11.1.0.7.0
I have an insert statement like following which is taking less than 2 secs to complete and inserts around 4000 rows:
INSERT INTO sch.tab1
(c1,c2,c3)
SELECT c1,c2,c3
FROM sch1.tab1@dblink
WHERE c1 IN (SELECT c1 FROM sch1.tab2@dblink);I wanted to change it to a MERGE statement just to avoid duplicate data. I changed it to following :
MERGE INTO sch.tab1 t1
USING (SELECT c1,c2,c3
FROM sch1.tab1@dblink
WHERE c1 IN (SELECT c1 FROM sch1.tab2@dblink) t2
ON (t1.c1 = t2.c1)
WHEN NOT MATCHED THEN
INSERT (t1.c1,t1.c2,t1.c3)
VALUES (t2.c1,t2.c2,t2.c3);The MERGE statement is taking more than 2 mins (and I stopped the execution after that). I removed the WHERE clause subquery inside the subquery of the USING section and it executed in 1 sec.
If I execute the same select statement with the WHERE clause outside the MERGE statement, it takes just 1 sec to return the data.
Is there any known issue with MERGE statement while implementing using above scenario?riedelme wrote:
Are your join columns indexed?
Yes, the join columns are indexed.
You are doing a remote query inside the merge; remote queries can slow things down. Do you have to select all thr rows from the remote table? What if you copied them locally using a materialized view?Yes, I agree that remote queries will slow things down. But the same is not happening while select, insert and pl/sql. It happens only when we are using MERGE. I have to test what happens if we use a subquery refering to a local table or materialized view. Even if it works, I think there is still a problem with MERGE in case of remote subqueries (atleast till I test local queries). I wish some one can test similar scenarios so that we can know whether it is a genuine problem or some specific problem from my side.
>
BTW, I haven't had great luck with MERGE either :(. Last time I tried to use it I found it faster to use a loop with insert/update logic.
Edited by: riedelme on Jul 28, 2009 12:12 PM:) I used the same to overcome this situation. I think MERGE needs to be still improved functionally from Oracle side. I personally feel that it is one of the robust features to grace SQL or PL/SQL. -
Indivual error recording in Merge Statement !!!!
Is it possible to record indivudual error in MERGE statement (Update / Insert).
I am unable to record those error. instead of MERGE if I update table in the cursor loop then I am able to record individual error but the process is time consuming.
Thanks in advance.
DebaHi Deba,
DML Error Logging:
SQL> create table tab1 (x number(1));
Table created.
SQL> exec dbms_errlog.create_error_log('tab1')
PL/SQL procedure successfully completed.
SQL>
SQL> merge into tab1 t
2 using (select 1 x from dual union all
3 select 112 x from dual) s
4 on (t.x = s.x)
5 when not matched
6 then insert (x) values (s.x)
7 log errors into err$_tab1 reject limit unlimited;
1 row merged.
SQL>
SQL> COL x for 9999
SQL> select * from tab1;
X
1
SQL> COL x for a4
SQL> select ora_err_number$, X from err$_tab1;
ORA_ERR_NUMBER$ X
1438 112
SQL>Regards
Peter -
Issue with Oracle Merge statements (PL/SQL: ORA-00913: too many values)
Hi All,
I am using the below merge statement and I am getting too many rows issues when I am compiling.
BEGIN
FOR te_rec IN ( SELECT /*+ parallel(ts,4) */ te.dtv_acct_num FROM telcos_eligible te, telcos_setup ts, telcos_partners tp
WHERE tp.telcos_name = UPPER((p_telcos_name))
AND ts.partner_id = tp.partner_id
AND te.ts_id = ts.ts_id ) LOOP
MERGE INTO tcs_accounts
USING (
SELECT /*+ DRIVING_SITE(a) */account_id, a.subscriber_id, status, account_type FROM account@tcs_to_paris a WHERE a.subscriber_id = te_rec.dtv_acct_num
) paris_accounts
ON (tcs_accounts.subscriber_id = paris_accounts.subscriber_id)
WHEN MATCHED THEN
UPDATE SET
account_type = paris_accounts.account_type,
subscriber_id = paris_acounts.subscriber_id,
status = paris_accounts.status
WHEN NOT MATCHED THEN
INSERT(account_id, subscriber_id, status_account_type)
VALUES(paris_accounts.account_id, paris_accounts.subscriber_id, paris_accounts.status, paris_accounts.account_type);
END LOOP;
END;
Can you let me know what is the issue here.
Thanks,
MK.Hi,
Maddy wrote:
... WHEN NOT MATCHED THEN
INSERT(account_id, subscriber_id, status_account_type)
VALUES(paris_accounts.account_id, paris_accounts.subscriber_id, paris_accounts.status, paris_accounts.account_type);This is one of the many times when a little formatting can really help you. Anybody can forget a column (or have an extra one, or type a _ when they mean ,) but if you write code like this
INSERT ( account_id, subscriber_id, status_account_type)
VALUES (paris_accounts.account_id, paris_accounts.subscriber_id, paris_accounts.status, paris_accounts.account_type);you might spot the error yourself.
Always format your code. When you post any formatted text on thsi site, type these 6 characters:
\(small letters only, inside curly brackets) before and after formatted text, to preserve spacing. -
Performance Tuning of a merge statement
Hi,
below query is occupying the temp tablespace(120GB) and explain planis not showing it .
Can someone please help me with this.
explain plan for MERGE INTO BKMAIN.BK_CUST_OD_PEAK_SUM TGT USING
WITH OD_MAIN AS
SELECT
MAX (
CASE
WHEN CUST_BAL_MAX.BK_TRN_TS <= CUST_BAL_TEMP.BK_TRN_TS
AND CUST_BAL_MAX.BK_CUR_BAL_RPT_CCY_AM >= 0
THEN CUST_BAL_MAX.BK_TRN_TS
ELSE NULL
END) T_TMP_TRN_TS,
MIN(
CASE
WHEN CUST_BAL_MAX.BK_TRN_TS >= CUST_BAL_TEMP.BK_TRN_TS
AND CUST_BAL_MAX.BK_CUR_BAL_RPT_CCY_AM >= 0
THEN CUST_BAL_MAX.BK_TRN_TS
ELSE NULL
END) T_TMP_TRN_TS1 ,
CUST_BAL_TEMP.BK_BUS_EFF_DT ,
CUST_BAL_TEMP.BK_CUR_BAL_RPT_CCY_AM ,
CUST_BAL_TEMP.BK_PDAY_CLS_BAL_RPT_CCY_AM ,
CUST_BAL_MAX.N_CUST_SKEY
FROM BKMAIN.BK_CUST_TRN_TM_BAL_SUM CUST_BAL_MAX ,
SELECT TRN_SUM.N_CUST_SKEY ,
TRN_SUM.BK_BUS_EFF_DT ,
TRN_SUM.BK_TRN_TS ,
TRN_SUM.BK_CUR_BAL_RPT_CCY_AM ,
CUST_OD_RSLT.BK_PDAY_CLS_BAL_RPT_CCY_AM
FROM BKMAIN.BK_CUST_TRN_TM_BAL_SUM TRN_SUM,
BKMAIN.BK_CUST_OD_PEAK_SUM CUST_OD_RSLT
WHERE (TRN_SUM.BK_BUS_EFF_DT = '02-APR-2013'
AND TRN_SUM.N_CUST_SKEY = CUST_OD_RSLT.N_CUST_SKEY
AND TRN_SUM.BK_BUS_EFF_DT = CUST_OD_RSLT.BK_BUS_EFF_DT
AND TRN_SUM.BK_CUR_BAL_RPT_CCY_AM= (-1*CUST_OD_RSLT.BK_MAX_OD_RPT_CCY_AM))
CUST_BAL_TEMP
WHERE CUST_BAL_MAX.BK_BUS_EFF_DT='02-APR-2013'
AND CUST_BAL_MAX.N_CUST_SKEY =CUST_BAL_TEMP.N_CUST_SKEY
AND CUST_BAL_MAX.BK_BUS_EFF_DT =CUST_BAL_TEMP.BK_BUS_EFF_DT
GROUP BY CUST_BAL_MAX.N_CUST_SKEY ,
CUST_BAL_TEMP.BK_BUS_EFF_DT ,
CUST_BAL_TEMP.BK_CUR_BAL_RPT_CCY_AM,
CUST_BAL_TEMP.BK_PDAY_CLS_BAL_RPT_CCY_AM
SELECT
N_CUST_SKEY,
BK_BUS_EFF_DT ,
CASE
WHEN T_TMP_TRN_TS IS NOT NULL
THEN
SELECT CUST_BAL.BK_CUR_BAL_END_TS
FROM BKMAIN.BK_CUST_TRN_TM_BAL_SUM CUST_BAL
WHERE CUST_BAL.BK_BUS_EFF_DT='02-APR-2013'
AND CUST_BAL.N_CUST_SKEY = OD_MAIN.N_CUST_SKEY
AND CUST_BAL.BK_TRN_TS = OD_MAIN.T_TMP_TRN_TS
WHEN (T_TMP_TRN_TS IS NULL
AND OD_MAIN.BK_PDAY_CLS_BAL_RPT_CCY_AM < 0)
THEN BK_FN_GET_STRT_EOD_BUS_TS(1, '02-APR-2013','S')
WHEN (T_TMP_TRN_TS IS NULL
AND OD_MAIN.BK_PDAY_CLS_BAL_RPT_CCY_AM >= 0)
THEN
SELECT MIN(CUST_BAL.BK_TRN_TS)
FROM BKMAIN.BK_CUST_TRN_TM_BAL_SUM CUST_BAL
WHERE CUST_BAL.BK_BUS_EFF_DT='02-APR-2013'
AND CUST_BAL.N_CUST_SKEY = OD_MAIN.N_CUST_SKEY
AND CUST_BAL.BK_OD_FL ='Y'
END T_MAX_OD_STRT_TS,
CASE
WHEN T_TMP_TRN_TS1 IS NOT NULL
THEN
SELECT CUST_BAL.BK_CUR_BAL_STRT_TS
FROM BKMAIN.BK_CUST_TRN_TM_BAL_SUM CUST_BAL
WHERE CUST_BAL.BK_BUS_EFF_DT='02-APR-2013'
AND CUST_BAL.N_CUST_SKEY = OD_MAIN.N_CUST_SKEY
AND CUST_BAL.BK_TRN_TS = OD_MAIN.T_TMP_TRN_TS1
WHEN (T_TMP_TRN_TS1 IS NULL )
THEN BK_FN_GET_STRT_EOD_BUS_TS(1, '02-APR-2013','E')
END T_MAX_OD_END_TS
FROM OD_MAIN
) SRC ON(TGT.N_CUST_SKEY = SRC.N_CUST_SKEY AND TGT.BK_BUS_EFF_DT = SRC.BK_BUS_EFF_DT AND TGT.BK_BUS_EFF_DT = '02-APR-2013')
WHEN MATCHED THEN
UPDATE
SET BK_MAX_OD_STRT_TS = T_MAX_OD_STRT_TS,
BK_MAX_OD_END_TS = T_MAX_OD_END_TS;
set linesize 2000;
select * from table( dbms_xplan.display );
PLAN_TABLE_OUTPUT
Plan hash value: 2341776056
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | MERGE STATEMENT | | 1 | 54 | 2035 (1)| 00:00:29 |
| 1 | MERGE | BK_CUST_OD_PEAK_SUM | | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID | BK_CUST_TRN_TM_BAL_SUM | 1 | 35 | 4 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | PK_BK_CUST_TRN_TM_BAL_SUM | 1 | | 3 (0)| 00:00:01 |
|* 4 | TABLE ACCESS BY INDEX ROWID | BK_CUST_TRN_TM_BAL_SUM | 1 | 35 | 4 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | PK_BK_CUST_TRN_TM_BAL_SUM | 1 | | 3 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
| 6 | SORT AGGREGATE | | 1 | 26 | | |
|* 7 | TABLE ACCESS BY INDEX ROWID | BK_CUST_TRN_TM_BAL_SUM | 1 | 26 | 9 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | PK_BK_CUST_TRN_TM_BAL_SUM | 5 | | 3 (0)| 00:00:01 |
| 9 | VIEW | | | | | |
| 10 | NESTED LOOPS | | | | | |
| 11 | NESTED LOOPS | | 1 | 173 | 2035 (1)| 00:00:29 |
| 12 | VIEW | | 1 | 61 | 2033 (1)| 00:00:29 |
| 13 | SORT GROUP BY | | 1 | 85 | 2033 (1)| 00:00:29 |
| 14 | NESTED LOOPS | | | | | |
| 15 | NESTED LOOPS | | 1 | 85 | 2032 (1)| 00:00:29 |
|* 16 | HASH JOIN | | 1 | 54 | 2024 (1)| 00:00:29 |
PLAN_TABLE_OUTPUT
|* 17 | TABLE ACCESS STORAGE FULL| BK_CUST_OD_PEAK_SUM | 18254 | 410K| 118 (0)| 00:00:02 |
|* 18 | TABLE ACCESS STORAGE FULL| BK_CUST_TRN_TM_BAL_SUM | 370K| 10M| 1904 (1)| 00:00:27 |
|* 19 | INDEX RANGE SCAN | PK_BK_CUST_TRN_TM_BAL_SUM | 5 | | 2 (0)| 00:00:01 |
|* 20 | TABLE ACCESS BY INDEX ROWID| BK_CUST_TRN_TM_BAL_SUM | 3 | 93 | 8 (0)| 00:00:01 |
|* 21 | INDEX RANGE SCAN | PK_BK_CUST_OD_PEAK_SUM | 1 | | 1 (0)| 00:00:01 |
| 22 | TABLE ACCESS BY INDEX ROWID | BK_CUST_OD_PEAK_SUM | 1 | 112 | 2 (0)| 00:00:01 |
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
2 - filter("CUST_BAL"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
3 - access("CUST_BAL"."N_CUST_SKEY"=:B1 AND "CUST_BAL"."BK_TRN_TS"=:B2)
4 - filter("CUST_BAL"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
5 - access("CUST_BAL"."N_CUST_SKEY"=:B1 AND "CUST_BAL"."BK_TRN_TS"=:B2)
7 - filter("CUST_BAL"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"CUST_BAL"."BK_OD_FL"='Y')
8 - access("CUST_BAL"."N_CUST_SKEY"=:B1)
16 - access("TRN_SUM"."N_CUST_SKEY"="CUST_OD_RSLT"."N_CUST_SKEY" AND
"TRN_SUM"."BK_BUS_EFF_DT"="CUST_OD_RSLT"."BK_BUS_EFF_DT" AND
"TRN_SUM"."BK_CUR_BAL_RPT_CCY_AM"=(-1)*"CUST_OD_RSLT"."BK_MAX_OD_RPT_CCY_AM")
17 - storage("CUST_OD_RSLT"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
PLAN_TABLE_OUTPUT
filter("CUST_OD_RSLT"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
18 - storage("TRN_SUM"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
filter("TRN_SUM"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
19 - access("CUST_BAL_MAX"."N_CUST_SKEY"="TRN_SUM"."N_CUST_SKEY")
20 - filter("CUST_BAL_MAX"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss')
AND "CUST_BAL_MAX"."BK_BUS_EFF_DT"="TRN_SUM"."BK_BUS_EFF_DT")
21 - access("TGT"."N_CUST_SKEY"="N_CUST_SKEY" AND "TGT"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02
00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
filter("TGT"."BK_BUS_EFF_DT"=TO_DATE(' 2013-04-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
53 rows selected.Hi
sb92075 wrote:
it appears that the STATISTICS do NOT reflect reallity; or do you really have many tables with 1 row?not necessarily (and not even likely)
1) explain plan shows expected number of rows after filters are applied, so even if stats are perfectly correct, but predicates are correlated, then it's easy to get cardinality = 1 because the optimizer has no way of knowing correlations between columns (unless you're in 11g and you have collected exteded stats on this colgroup)
2) in explain plan, cardinalities of driven operations are show per 1 iterantion. E.g.:
NESTED LOOP cardinality = 1,000,000
TABLE ACCESS FULL A cardinality = 1,000,000
TABLE ACCESS BY ROWID B cardinality = 1
INDEX UNIQUE SCAN PK$B cardinality = 1doesn't mean that the optimizer expects to find 1 row in table B, with or without filters, it means that there will be 1 row per each of 1,000,000 iterations.
In this specific case, the most suspicious operation in the plan is HASH JOIN 16: first, because it's highly unusual to have 18k rows in one table and 370k in another
and find only 1 match; second, because it's a 3-column join, which probably explains why the join cardinality is estimated so low.
Often, such problems are mitigated by multicolumn join sanity checks, so maybe the OP is either on an old version of Oracle that doesn't have these checks, or these checks are disabled for some reason.
Best regards,
Nikolay -
Looping thru instance manager and checking radio button selected
I need to loop thru my instances and toggle visible/hidden if a particular radio button in each instance is selected.
My code right now does not work but I feel I am on the right track (minus the else statement it will need to toggle on/off).
Can anyone help? thanks in advance!
var rowCount = BugGroup_f.instanceManager.count;
for (i=0; i<rowCount; i++) {
var str = xfa.resolveNode("BugGroup_f.detail3.bugInfo.BugItem.status.RadioButtonList[" + i + "]").rawValue;
if (str.indexOf("Fixed") > -1) {
xfa.resolveNode("BugGroup_f["+rowCount+"]").presence = "hidden"So we've got a set of Rows, each with a subitem called RadioToggle, and you want to go through and set them all, then click a separate button and hide the ones with "on" radio buttons?
function ToggleRows(reset){
var Rows = Form.subform....BugGroup_f.all;
var curRow;
for (var i=0; i<Rows.length; i++){
curRow = Rows.item(i);
if ((curRow.RadioButton.rawValue == "WhatevermeansHidden") && !reset){
curRow.presense = "hidden";}
else{
curRow.presense = "visible";}
^ in a script object, and put
scriptObjectName.ToggleRows(reset);
in the click event of your button, and you should be golden.
If you do want them to hide the moment you click the toggle, you could put this, right?
if (xfa.event.newText == "whatevermeansoff"){
parent....presense = "hidden";}
The .all method seems like a much easier way to handle collections of objects, and specificaly collections of instances. It also means you can do relative referencing, i.e. to create a function that will operate on all the rows of a table, without knowing which table it is operating on, so a button in each table can pass it's parent table to the function.
var GroupVariable = Object.all
for(var i=0; i < GroupVariable.length; i++)
EDIT:
add a reset value, and pass it in to your function like above (added).
make a separate button, or control, that will call the function with reset = 1.
Maybe you are looking for
-
Multiple rows in a single but with different column names
Hello All, I have a table in which data is stored in the below displayed fashion. TRANS_ID Ty_1 NU_1 38960 BP 5215153159 38960 EM [email protected] 38960 FX 5115538033 38960 HP 4419965055 38960 For some weir
-
Question about replacing corrupted file in windows 7
hi, I read in windows 7 bible that if a system file is corrupted , I can replace it with system recovery tool (at command prompt) if I have onother computer with windows 7 installed. my question is here , if I replace any file with copy the file fro
-
Hi Friends, Normally we use SAP Defined BAPI'S in our programs, but why we need to use Custom DEFINED BAPI'S ? Is there any reason ? thanks and regards Vijaya Points for sure
-
How to order Photoshop always opening images in IDCS4?
In the Links window it appears Illustrator as the default for opening images!!! Applying the option key over an image opens it in Illustrator... Would like to have Photoshop as the default. It is a Mac or an Adobe preference?
-
Trouble with loadMasters function.
Hey everybody, I'm trying to automate the replacement of a number of master spreads across many documents. Unfortunately, I keep getting the following error: Error Number: 48 Error String: Cannot find the folder " ". Both of these code snippets give