Reputation: 65
I am trying to create a PL/SQL
block to update a empty column, is_true
, in a new table created_table
on the basis of another table, table1
. The id
fields on the tables match and there are no rows in created_table
that doesn't have a corresponding row in table1
. I'm basing the update on the status column of table1
, but instead of 'Yes' and 'No', I need it reflected as 'Y' and 'N':
created_table: expected results:
id | is_true | other columns id | is_true | other columns
---|---------|-------------- ---|---------|--------------
1 | null | ... 1 | 'Y' | ...
2 | null | ... 2 | 'N' | ...
table1:
id | status | other columns
---|--------|--------------
1 | 'Yes' | ...
2 | 'No' | ...
Since created_table
is very large, I'm trying to update it using a PL/SQL
procedure, so that in case of failure midway, I'll still have updated rows. The next run of the procedure can then pick up where it previously failed without processing already processed rows.
I've tried testing with this code block:
DECLARE
is_true varchar2 (5) created_table.is_true%type;
BEGIN
FOR status IN (SELECT a.status
from table1 a
left join created_table b
where and a.id=b.id )
LOOP
IF status = 'Yes' THEN
UPDATE created_table SET is_true= 'Y'
ELSE
UPDATE created_table SET is_true= 'N'
WHERE ROWNUM := status.ROWNUM
END IF;
DBMS_OUTPUT.PUT_LINE('Done');
END LOOP;
END;
But it's giving me errors:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
What can I do to make it work?
Upvotes: 2
Views: 218
Reputation: 3166
Your code had multiple errors:
DECLARE
-- is_true varchar2 (5) created_table.is_true%type; -- PLS-00103: Encountered the symbol "CREATED_TABLE" when expecting one of the following:
is_true created_table.is_true%type;
BEGIN
FOR status IN (SELECT a.status
from table1 a
-- left join created_table b -- ORA-00905: missing keyword
-- where and a.id=b.id )
left join created_table b on a.id = b.id)
LOOP
-- IF status = 'Yes' THEN -- PLS-00306: wrong number or types of arguments in call to '='
IF status.status = 'Yes' THEN
-- UPDATE created_table SET is_true= 'Y' -- ORA-00933: SQL command not properly ended
UPDATE created_table SET is_true= 'Y';
ELSE
UPDATE created_table SET is_true= 'N'
-- WHERE ROWNUM := status.ROWNUM -- ORA-00920: invalid relational operator and ORA-00933: SQL command not properly ended
WHERE ROWNUM = status.ROWNUM;
END IF;
DBMS_OUTPUT.PUT_LINE('Done');
END LOOP;
END; -- PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
/
The PLS-00103
is really just telling you that a /
is missing. After that the remaining error is PLS-00302: component 'ROWNUM' must be declared
. From "Oracle Database Online Documentation": rownum is a pseudocolumn.
Your SQL
would update every row in the table setting is_true
to 'Y'
on the first encounter of status
being 'Yes'
, since you didn't give it a WHERE
clause. I'm assuming that is not your intent.
There was also no COMMIT
in your PL/SQL
block, so in effect it would have been the same as running a normal SQL
.
Based on the situation you've described, I made some changes to the code block. This will provide with a limit for how many rows can be processed prior to a COMMIT
. I set the limit to 5. You should change that to something appropriate. It will not pick up any rows that have empty values for is_true
, so in effect it will only work on non-processed rows:
DECLARE
commit_counter PLS_INTEGER := 1; -- count commits
commit_limit PLS_INTEGER := 5; -- rows for commit limit
counter PLS_INTEGER := commit_limit;
BEGIN
FOR rec IN (SELECT a.status, a.id
FROM created_table b
JOIN table1 a ON a.id = b.id
WHERE b.is_true IS NULL) -- do not pick up processed rows
LOOP
IF rec.status = 'Yes' THEN
UPDATE created_table SET is_true = 'Y'
WHERE id = rec.id;
ELSE
UPDATE created_table SET is_true = 'N'
WHERE id = rec.id;
END IF;
counter := counter - 1;
IF counter < 1 THEN
counter := commit_limit; --reset counter
commit_counter := commit_counter + 1;
COMMIT;
END IF;
END LOOP;
COMMIT; -- all rows are processed;
DBMS_OUTPUT.PUT_LINE(commit_counter || ' COMMITS');
END;
/
This will update all the rows in one go, still only updating the "empty" rows:
UPDATE created_table b
SET is_true = (SELECT CASE a.status WHEN 'Yes' THEN 'Y'
ELSE 'N'
END
FROM table1 a
WHERE a.id = b.id)
WHERE b.is_true IS NULL;
Upvotes: 1