Can't Solve ora-06550 pls-00103 ERROR in Qyery - oracle

I wrote the following query to Update Table EMPSHIFT VALUES From SCHEDULEEMPLOYEES
Table but get the following Error ora-06550 pls-00103 and can't solve it
so what is the problem
DECLARE
day_date DATE:=TO_DATE('01/04/2017','DD/MM/YYYY');
BEGIN
LOOP
FOR employees IN (SELECT EmpID FROM EMPSHIFT)
LOOP
EXECUTE IMMEDIATE
' UPDATE EMPSHIFT SET EMPSHIFT."'||TO_CHAR(day_date)||'" =
(
SELECT SCHEDULEEMPLOYEES.SCHEDULEID ||'-'|| SCHEDULEEMPLOYEES.SHIFTS
FROM SCHEDULEEMPLOYEES INNER JOIN EMPSHIFT ON SCHEDULEEMPLOYEES.EMPLOYEEID = EMPSHIFT.EMPLOYEEID
WHERE SCHEDULEEMPLOYEES.DAYDATE = '||TO_CHAR(day_date)||' and EMPSHIFT.EMPLOYEEID = ' || employees.EmpID ||'
)
WHERE EMPSHIFT.EMPLOYEEID =' ||employees.EmpID ||';';
day_date = day_date + 1;
EXIT
WHEN day_date >TO_DATE('30/04/2017','DD/MM/YYYY');
END LOOP;
END LOOP;
END;

1) As others mentioned,"day_date = day_date + 1;" has missing the correct assignment operator ":=".
2) The "EXECUTE..." part is not required here. Why are You using it?
3) What is your goal? The current structure looks "weird". The first loop statement has no control of the flow, only the inner one has, but its loop iterations is only based on the employees count, not the dates.
4) Is the update statement correct? I mean the "set empshift.<..>. I doubt, he has an attribute named "01/04/2017".
Created an example,:
declare
l_day_date date:=to_date('01/04/2017','DD/MM/YYYY');
l_res varchar2(400);
begin
loop
for l_emp in (select emp_id from empshift_test_v)
loop
dbms_output.put_line('the emp_id is :'||l_emp.emp_id);
--update empshift_test_v etv
--set etv.empshift_code/*<correct_att_name>*/ = (
select
nvl((select
sct.sch_id ||'-'|| sct.shifts shift_code
from
SCHEDULEEMPLOYEES_TEST_V sct,
empshift_test_v etv1
where
sct.day_date = l_day_date and
sct.emp_id = etv1.emp_id and
etv1.emp_id = l_emp.emp_id),'no_info')
into
l_res
from
empshift_test_v etv
where
etv.emp_id = l_emp.emp_id;
dbms_output.put_line('day_date is :'||to_char(l_day_date,'DD/MM/YYYY'));
dbms_output.put_line('l_res is :'||l_res);
end loop;
l_day_date := l_day_date + 1;
exit when l_day_date >to_date('30/04/2017','DD/MM/YYYY');
end loop;
end;
WHERE views "EMPSHIFT_TEST_V" and "SCHEDULEEMPLOYEES_TEST_V" has info like:
enter image description here
Hope it helps.
UPDATE:
Modified it according to you data.
declare
l_day_date date:=to_date('01/04/2017','DD/MM/YYYY');
l_res number;
l_stmt varchar2(4000);
begin
loop
for l_emp in (select emp_id from empshift_test)
loop
dbms_output.put_line('the emp_id is :'||l_emp.emp_id);
begin
select
sct.shift
into
l_res
from
SCHEDULEEMPLOYEES_TEST sct,
empshift_test etv
where
sct.daydate = l_day_date and
sct.emp_id = etv.emp_id and
etv.emp_id = l_emp.emp_id;
exception
when NO_DATA_FOUND then
l_res := 0;
end;
dbms_output.put_line('day_date is :'||to_char(l_day_date,'DD/MM/YYYY'));
dbms_output.put_line('l_res is :'||l_res);
if l_res > 0 then
l_stmt := 'update empshift_test emp
set emp."'||to_char(l_day_date,'DD/MM/YYYY')||'" = '||l_res||'
where emp.emp_id = '||l_emp.emp_id||';';
dbms_output.put_line('l_stmt is :'||l_stmt);
execute immediate l_stmt;
end if;
end loop;
l_day_date := l_day_date + 1;
exit when l_day_date >to_date('30/04/2017','DD/MM/YYYY');
end loop;
end;
But there is a catch: if you run the DML statement manually - it works, but with execute immediate - it throws error ora-00933. He cant read the number column for some reason.
Another good stack question to solve:)
So the plan is:
1) Change the table structure; or
2) Solve the problem, when calling a attribute, named as number (with symbols like "/") using execute immediate.

Related

DBMS_PARALLEL_EXECUTE exiting without running task

For large loads, we generally prefer to execute it in parallel and hence Oracle package DBMS_PARALLEL_EXECUTE. Here we are using chunking by row. When I run this, I am getting
ORA-29495: invalid state for resume task
Task status is CHUNKED and chunks are in UNASSIGNED status.
What is going on here?
declare
l_sql varchar2(500);
l_chunk_sql varchar2(500);
l_task_nm varchar2(50):='k_clearance_1';
l_try number:=0;
l_status number;
l_count number:=0;
begin
select count(1)
into l_count
from user_parallel_execute_tasks
where task_name=l_task_nm;
--create task if not exist
if l_count = 0 then
--create task
dbms_parallel_execute.create_task(l_task_nm);
end if;
--create chunk
dbms_parallel_execute.create_chunks_by_rowid(
task_name=>l_task_nm,
table_owner=>'RXTEAM',
table_name=>'RPM_STAGE_CLEARANCE_ID_FIX',
by_row=>TRUE,
chunk_size=>10000
);
l_sql := 'update XXXXXX krsc
set krsc.lgcy_extr_tmst = sysdate
where exists (select 1
from rxteam.rpm_stage_clearance_id_fix rscf
where rscf.rpm_stage_clearance_id=krsc.rpm_stage_clearance_id
and rscf.rowid between :start_id and :end_id)';
--run task
dbms_parallel_execute.run_task(task_name=>l_task_nm,
sql_stmt=>l_sql,
language_flag=>DBMS_SQL.NATIVE,
parallel_level=>40
);
l_try := 0;
l_status := DBMS_PARALLEL_EXECUTE.task_status(l_task_nm);
while (l_try < 2 and l_status != DBMS_PARALLEL_EXECUTE.FINISHED)
loop
l_try := l_try + 1;
DBMS_PARALLEL_EXECUTE.resume_task(l_task_nm);
l_status := DBMS_PARALLEL_EXECUTE.task_status(l_task_nm);
end loop;
--dbms_parallel_execute.drop_task(l_task_nm)
end;
/
In my case the problem was a (parse) error in the code of the PL/SQL anonymous block I submitted. I found out by looking in the USER_SCHEDULER_JOB_RUN_DETAILS table.
This might help:
SELECT t.task_name, t.sql_stmt, d.errors
--, d.* -- uncomment to see all job detail information
FROM user_parallel_execute_tasks t
JOIN user_scheduler_job_run_details d ON d.job_name = t.job_prefix||'_1'
WHERE t.status = 'CHUNKED'
ORDER BY t.task_name, d.job_name;

Where clause in Dynamic sql

I am trying to get all the tables where bank_id is 01.
I have written the following block
DECLARE
cursor cBankId is
select owner||'.'||table_name from all_tab_columns where column_name = 'BANK_ID';
v_table all_tab_columns.table_name%TYPE;
vcount varchar2(50);
BEGIN
open cBankId;
loop
fetch cBankId into v_table;
exit when cBankId%notfound;
execute immediate 'select count(*) from ' || v_table into vcount || ' where bank_id = 01';
IF vcount > 0 THEN
DBMS_OUTPUT.PUT_LINE (v_table);
END IF;
end loop;
close cBankId;
END;
I want to know how to put where clause in the execute immediate statement .
I am getting the error
ORA-06550: line 15, column 67:
PLS-00103: Encountered the symbol "|" when expecting one of the following:
. ( , % ; return returning using
You only need to change the order you're writing the parts of your query.
When using dynamic SQL, you need something like this:
SQL> declare
2 v_table varchar2(30);
3 vCount number;
4 begin
5 v_table := 'dual';
6 execute immediate 'select count(*) from ' || v_table || ' where 1=1' into vcount;
7 --
8 dbms_output.put_line('vCount: ' || vCount);
9 end;
10
11 /
vCount: 1
PL/SQL procedure successfully completed.
That is: execute immediate 'select ... from ... where ...' INTO ...;
You can't dynamically use a variable for the table name, instead use:
DECLARE
cursor cBankId is
select owner||'.'||table_name from all_tab_columns where column_name = 'BANK_ID';
v_table all_tab_columns.table_name%TYPE;
vcount varchar2(50);
v_sql varchar2(1000);
BEGIN
open cBankId;
loop
fetch cBankId into v_table;
exit when cBankId%notfound;
v_sql := 'select count(*) from ' || v_table || ' into vcount where bank_id = 01';
execute immediate v_sql;
IF vcount > 0 THEN
DBMS_OUTPUT.PUT_LINE (v_table);
END IF;
end loop;
close cBankId;
END;

Errors in PL/SQL

I was trying to create a PL/SQL program to search for a value in entire database. Following is the code:
DECLARE
custom_query VARCHAR2(100);
user_input VARCHAR2(100);
i NUMBER (6);
TYPE temp_record
IS
varray(1000) OF VARCHAR2(100);
CURSOR t_rec IS
SELECT a.name AS t_name,
b.name AS c_name
FROM sys.TABLES a,
sys.COLUMNS b
WHERE a.object_id = b.object_id;
table_rec t_name%ROWTYPE;
BEGIN
IF NOT t_rec%isopen THEN
OPEN t_rec;
END IF;
FETCH t_rec
INTO table_rec;
WHILE t_rec%FOUND THEN
LOOP
custom_query := 'select'
|| table_rec.c_name
|| 'into temp_record from'
||table_rec.t_name ;
dbms_output.Put_line(custom_query);
EXECUTE IMMEDIATE custom_query;
FOR i IN 1 .. temp_record.count
LOOP
IF (Temp_record(i) = user_input) THEN
dbms_output.Put_line ('The value you are looking for is in '
|| table_rec.c_name
|| 'column of table'
|| table_rec.t_name);
END IF;
END LOOP;
END LOOP;
END;
Can anyone let me know what's wrong with this code?
Use ALL_TAB_COLUMNS to iterate all tables and columns in your dynamic query.

Need help in execute immediate update query

I have this query and it's not updating into the database. The given "where" clause is valid. When I run the query independently, it works fine but in this Procedure it's not working. There is no exception or no error. Could you guys help me in figuring out where the problem is?
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET COUNTRY_CODE = :v1 WHERE col_id = :v2'
USING l_vc_CountryCode, l_vc_ColId;
if SQL%ROWCOUNT > 1 THEN
inserts := inserts + 1;
counter := counter + 1;
IF counter > 500 THEN
counter := 0;
COMMIT;
END IF;
END IF;
I didn't write the commit code before. Just to clarity.
I suppose that col_id is the primary key. So in the update statement
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET COUNTRY_CODE = :v1 WHERE col_id = :v2'
USING l_vc_CountryCode, l_vc_ColId;
you are always updating at most one row and thus the condition
SQL%ROWCOUNT > 1
is never true ( 1 is not > 1 )
So if you don't have any other commit statement in your procedure, you will never commit those updates.
By the way: what is the purpose of this
if SQL%ROWCOUNT > 1 THEN
inserts := inserts + 1;
counter := counter + 1;
IF counter > 500 THEN
counter := 0;
COMMIT;
END IF;
END IF;
why don't you just commit at the end of your work?
The following code works okay (ie updates the row).
I suspect your error is elsewhere.
For example, if you don't initialise COUNTER, the increment will still leave it as null and it will never commit.
Or, l_vc_ColId may be the wrong datatype and suffering from an invalid conversion.
declare
v_emp_id number := 7839;
v_name varchar2(4) := 'DING';
v_tab varchar2(3) := 'EMP';
begin
execute immediate 'update '||v_tab||
' set ename = :v_name Where empno = :v_emp_id'
using v_name, v_emp_id;
dbms_output.put_line('C:'||sql%rowcount);
end;
you may want to reconsider your design if your using dynamic sql to change the "dest" table in thousands of updates.
Much better to know your dest and use bind variables for the where conditions. then you can commit every x rows using mod or similar:
if (mod(v_ctr, 1000) = 0) then
commit;
end if;
But for your example, Marcin is correct, if you are updating only 1 row at a time, then
if SQL%ROWCOUNT > 1
will never be true;
EDIT:
A simple example knowing your "dest" table:
declare
cursor sel_cur is
select col1, col2, from sourceTable where col3 = 'X';
v_ctr pls_integer := 0;
begin
for rec in sel_cur
loop
v_ctr := v_ctr + 1;
-- implicit bind variables used
update destTable
set col1 = rec.col1,
col2 = rec.col2
where col3 = 'Z';
if (mod(v_ctr, 1000) = 0) then
commit;
end if;
end loop;
exception
when others then rollback;
raise;
end;
If using dynamic SQL, a simple example using explicit bind variables (USING clause) from Oracle docs:
CREATE OR REPLACE PROCEDURE raise_emp_salary (column_value NUMBER,
emp_column VARCHAR2, amount NUMBER) IS
v_column VARCHAR2(30);
sql_stmt VARCHAR2(200);
BEGIN
-- determine if a valid column name has been given as input
SELECT COLUMN_NAME INTO v_column FROM USER_TAB_COLS
WHERE TABLE_NAME = 'EMPLOYEES' AND COLUMN_NAME = emp_column;
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value;
IF SQL%ROWCOUNT > 0 THEN
DBMS_OUTPUT.PUT_LINE('Salaries have been updated for: ' || emp_column
|| ' = ' || column_value);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Invalid Column: ' || emp_column);
END raise_emp_salary;
/
For more reading, see here.
Hope this helps, happy coding
Execute immediate needs explicit commit. I guess you checked that ?

ORA-01775: looping chain of synonyms but there are no synonyms

Can't figure out why I'm getting 'SQL Statement ignored' and 'ORA-01775: looping chain of synonyms' on line 52 of this stored procedure. Got any ideas?
CREATE OR REPLACE PACKAGE PURGE_LOG_BY_EVENT_DAYS AS
TYPE dual_cursorType IS REF CURSOR RETURN dual%ROWTYPE;
PROCEDURE log_master_by_event_days (event_id NUMBER, purge_recs_older_than NUMBER, result_cursor OUT dual_cursorType);
END PURGE_LOG_BY_EVENT_DAYS;
/
CREATE OR REPLACE PACKAGE BODY PURGE_LOG_BY_EVENT_DAYS
AS
err_msg VARCHAR2(4000);
PROCEDURE log_master_by_event_days (event_id NUMBER, purge_recs_older_than NUMBER, result_cursor OUT dual_cursorType)
IS
TYPE type_rowid IS TABLE OF ROWID INDEX BY BINARY_INTEGER;
TYPE type_ref_cur IS REF CURSOR;
l_rid type_rowid;
c1 type_ref_cur;
l_sql_stmt VARCHAR2(4000);
proc_start_time DATE := sysdate;
purge_date DATE;
l_bulk_collect_limit NUMBER := 1000;
retry NUMBER := 5;
retry_count NUMBER := 0;
loop_count NUMBER := 0;
err_code VARCHAR2(10);
BEGIN
purge_date := to_date(sysdate - purge_recs_older_than);
l_sql_stmt := '';
l_sql_stmt := l_sql_stmt ||' SELECT rowid FROM LOG_MASTER ';
l_sql_stmt := l_sql_stmt ||' WHERE last_changed_date < :purge_date';
l_sql_stmt := l_sql_stmt ||' AND event_id = :event_id';
-- The following while loop
-- executes the purge code
-- 'retry' number of times in case of ORA-01555
WHILE retry > 0 LOOP
BEGIN
-- START of purge code
OPEN c1 FOR l_sql_stmt USING purge_date, event_id;
LOOP
FETCH c1 BULK COLLECT into l_rid LIMIT l_bulk_collect_limit;
FORALL i IN 1..l_rid.COUNT
DELETE from log_master
WHERE rowid = l_rid(i);
COMMIT;
loop_count := loop_count + 1;
EXIT WHEN c1%NOTFOUND;
END LOOP;
CLOSE c1;
-- End of purge code
-- if processing reached this point
-- Process completed successfuly, set retry = 0 to exit loop
retry := 0;
EXCEPTION
WHEN OTHERS THEN
-- ====================================
-- Get error msg
-- ====================================
ROLLBACK;
err_code := sqlcode;
dbms_output.put_line(err_code);
-- ====================================
-- Check if it is 01555
-- if so retry, else exit loop
-- ====================================
retry := retry - 1;
if err_code = '-1555' and retry > 0 THEN
CLOSE c1;
retry_count := retry_count + 1;
else
err_msg := sqlerrm;
exit;
end if;
END;
END LOOP;
IF err_msg IS NULL THEN
open result_cursor for select '1 - PURGE_LOG_BY_EVENT_DAYS ran successfully (event_id : '||event_id||', loop_count : '||loop_count||', bulk_limit : '||l_bulk_collect_limit||', retries : '||retry_count||') ' from dual;
ELSE
open result_cursor for select '2 - PURGE_LOG_BY_EVENT_DAYS After (event_id : '||event_id||', loop_count : '||loop_count||', bulk_limit : '||l_bulk_collect_limit||', retries : '||retry_count||') with Error: ' || err_msg from dual;
END IF;
END log_master_by_event_days;
END PURGE_LOG_BY_EVENT_DAYS;
I have no idea why you're getting the synonym error. But that's a lot of code for something that should be a single DELETE statement. I assume you've changed it to commit-every-n to avoid rollback errors. It would be nice if you could get your DBA to increase the undo space so you can actually do the work you need to do. Failing that, I think you can still make it much simpler:
LOOP
DELETE FROM log_master
WHERE last_changed_date < :purge_date
AND event_id = :event_id
AND rownum <= :batch_delete_limit
USING purge_date, event_id, l_bulk_collect_limit;
EXIT WHEN SQL%NOTFOUND;
END LOOP;
And you can throw your retry logic around that if you want.
Apologies if I've missed some subtlety that makes this different from what you're doing.
SELECT table_owner, table_name, db_link
FROM dba_synonyms
WHERE owner = 'PUBLIC' and db_link is not null
returns 0 rows
as far as i know, there are no synonyms.......

Resources