I have an application engine and i'm trying to do a try catch for record.insert in peoplecode action
But it seems that if the insert encountered an error in between, the rows prior to the error were rollback and only the rows after the error were being committed
for &i = 1 to &rowset.activerowcount
try
...
record.insert
catch exception..
end-try..
end-for
row 1 - not inserted
row 2 - not inserted
row error
row 3 - inserted
row 4 - inserted
does try catch really behaves this way?
Is there any way that row 1 and 2 will also be inserted into the database?
thanks
Try putting a commitwork() in the for loop.
CommitWork();
Related
I just started working with PL/SQL. The database is for a game I want to integrate into my discord bot. Both the DB and the bot are running on Oracle Cloud.
The DB has one table, players, consisting of a discord user id, they have a level initiated with 1, exp initiated with 0 and mana initiated with 100. For now, the first thing I wanted to implement was a TRIGGER that would activate when exp is updated on table players, check if exp reached the level up threshold and if so, reduce exp to 0 and increase the level by 1.
Right now, I have this:
CREATE OR REPLACE trigger level_up
BEFORE UPDATE
ON PLAYERS
FOR EACH ROW
WHEN (:new.EXP >= PLAYERS.LEVEL * 100)
begin
:new.EXP := 0;
:new.LEVEL := :old.LEVEL + 1;
end;
When I try to run this, I get the following error:
"Error: ORA-00904: : invalid identifier"
Nothing is highlighted and in SQL Developer, when I right-click it and then click "Go to source", it doesn't highlight anything and just throws the cursor to the beginning of the worksheet.
I have already tried a couple different things like
BEFORE UPDATE OF EXP ON PLAYERS
with the rest more or less the same and even tried working with AFTER UPDATE:
CREATE OR REPLACE trigger level_up
AFTER UPDATE
ON PLAYERS
FOR EACH ROW
begin
UPDATE players
SET players.exp = 0,
players.level = players.level + 1
WHERE players.exp < players.level * 100
end;
This gave me multiple errors though:
Error(6,9): PL/SQL: SQL Statement ignored
Error(10,5): PL/SQL: ORA-00933: SQL command not properly ended
Error(10,8): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge json_exists json_value json_query json_object json_array
At this point I am fully prepared to just abandon the oracle db and switch to mongodb or something, it's just bugging me out that I can't figure out what I am doing wrong.
Thank you for your time!
If the 1st trigger code is OK to you, then just fix what's wrong - why abandoning the whole idea of using Oracle? It's not its (Oracle's fault) you don't know how to use it.
Here's an example.
Table contains just two columns, necessary for this situation.
Column name can't be just level - that's name of a pseudocolumn in hierarchical query and is reserved word for that purpose; I renamed it to c_level (well, you can name it level, but it should then be enclosed into double quotes and you'd have to reference it that way - with double quotes - every time you access it, using exactly the same letter case. In Oracle, that's generally a bad idea).
SQL> create table players
2 (exp number,
3 c_level number
4 );
Table created.
Trigger: you should have removed colon when referencing the new pseudorecord in the when clause (while in trigger body you have to use it, the colon sign). Also, you don't reference c_level with table's name (players.c_level) but also using the pseudorecord.
SQL> create or replace trigger level_up
2 before update on players
3 for each row
4 when (new.exp >= new.c_level * 100)
5 begin
6 :new.exp := 0;
7 :new.c_level := :old.c_level + 1;
8 end;
9 /
Trigger created.
Let's try it. Initial row:
SQL> insert into players (exp, c_level) values (50, 1);
1 row created.
SQL> select * from players;
EXP C_LEVEL
---------- ----------
50 1
Let's update exp so that its value forces trigger to fire:
SQL> update players set exp = 101;
1 row updated.
New table contents:
SQL> select * from players;
EXP C_LEVEL
---------- ----------
0 2
SQL>
If that was your intention, then it kind of works.
I am trying to bulk insert rows from one table to another. I want to skip any errors that occur while doing this but log them as well. I used the following PL/SQL command to create an error log table for the table I am trying to insert all the values into:
BEGIN
DBMS_ERRLOG.create_error_log (
dml_table_name => 'ROBOT_ID_TOOL_DUMP_IDPK.TEST'
, skip_unsupported => TRUE);
END;
I then do a simple insert with logging turned on:
INSERT INTO table2
SELECT * FROM table1
LOG ERRORS INTO ERR$_table2;
The logging works but my insert is stopping, and rolling back after the first exception is hit (PK or unique constraint for example). I don't want to rollback when an exception is encountered though, I want that row to be skipped, and to continue trying to insert all remaining rows (but logging the problem row). I thought that is what the skip_unsupported parameter was doing. I have tried setting this value to FALSE and am still encountering the same issue.
I missed a step on my insert.
INSERT INTO table2
SELECT * FROM table1
LOG ERRORS INTO ERR$_table2 REJECT LIMIT UNLIMITED;
The REJECT LIMIT UNLIMITED flag Continues through every error.
I'm a newbie with sql triggers and am getting an ESQLiteException on what seems like a simple example. When I try to modify the "memberTag" column in an existing row, I get the exception "no such column: memberTag". If I drop the trigger, the exception goes away and the row gets updated.
I'm using SQLite and I'm using the "SQLite Expert Personal" app to do this experimenting.
I have this table:
CREATE TABLE [znode] (
[description] CHAR NOT NULL,
[memberTag] CHAR);
and this trigger:
CREATE TRIGGER [memberTagTrigger]
AFTER UPDATE
ON [znode]
FOR EACH ROW
WHEN length(memberTag)=0
BEGIN
update znode
set memberTag = null;
END;
My update experiment data is something like this:
description memberTag
one x
two (null)
And when I try to change (null) to "y" using SQLite Expert Personal, it throws the exception.
The problem is in the WHEN clause: the database does not know where memberTag comes from, because there are two possible rows, the old one, and the new one.
Use either OLD.memberTag or NEW.memberTag.
(There is another problem: the UPDATE will change all rows in the table, because you forgot the WHERE clause.)
I am new to Oracle (11gr2) and I have the following script:
BEGIN
DECLARE
source varchar2(1);
BEGIN
dbms_output.enable;
BEGIN
EXECUTE IMMEDIATE 'DROP VIEW SP_AD;';
SELECT SOURCE INTO source FROM map_switch WHERE ROWNUM = 1;
IF source = 'A'
THEN
EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
EXECUTE IMMEDIATE 'RENAME TABLE SP_AD_A TO SP_AD;';
ELSE
EXECUTE IMMEDIATE 'DROP TABLE SP_AD_A;';
EXECUTE IMMEDIATE 'RENAME TABLE SP_AD_B TO SP_AD;';
END IF;
COMMIT WORK;
dbms_output.put_line('SP_AD table issue fixed');
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Exception, rolling back transaction, SP_AD not resolved.');
ROLLBACK WORK;
END;
END;
END;
/
Essentially, its determining which table to drop, then it drops the view and renames the other table.
If I run the statements individually, it works perfectly well, but in the script above, it returns procedure executed successfully but nothing was executed.
I'm suspecting that its rolling back for some odd reason, but I'm hesitating to execute it without the rollback in place (these tables have in excess of 300,000 records).
Can someone tell me what's wrong and also, is there something wrong with my exception block?
As pointed out by commenters, there are a few reasons why your code isn't working as expected.
Firstly, don't use semicolons inside the strings that you pass to EXECUTE IMMEDIATE, as doing that will give you an ORA-00911 'invalid character' error:
SQL> BEGIN
2 EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
3 END;
4 /
BEGIN
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 2
After running this, you can then verify that the table still exists:
SQL> SELECT * FROM SP_AD_B;
no rows selected
(I don't have your table SP_AD_B, so I just created one named SP_AD_B with a single integer column in it. I didn't bother putting any data in it.)
If you remove the semicolon inside the string, not the one outside, it works:
SQL> BEGIN
2 EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B';
3 END;
4 /
PL/SQL procedure successfully completed.
SQL> SELECT * FROM SP_AD_B;
SELECT * FROM SP_AD_B
*
ERROR at line 1:
ORA-00942: table or view does not exist
Now that the table's gone, we get an error attempting to query it.
Hopefully, this should allow you to fix your script so that it works and drops the relevant tables.
But why weren't you getting any helpful information in your output message? Well, let's recreate the SP_AD_B table, and reintroduce the semicolon, and try dropping the table again, but with an EXCEPTION handler similar to yours:
SQL> BEGIN
2 EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
3 EXCEPTION
4 WHEN OTHERS THEN
5 dbms_output.put_line('Exception, rolling back transaction, SP_AD not resolved.');
6 END;
7 /
Exception, rolling back transaction, SP_AD not resolved.
PL/SQL procedure successfully completed.
In this case, we got an error message telling us something went wrong, so the table wasn't dropped. But what went wrong? There are thousands of errors that Oracle can report, and it can be difficult to guess what the problem is without knowing the error message.
There are a number of approaches you can take here. Firstly, you could write the error message, in SQLERRM to dbms_output:
SQL> BEGIN
2 EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
3 EXCEPTION
4 WHEN OTHERS THEN
5 dbms_output.put_line('Exception, rolling back transaction, SP_AD not resolved.');
6 dbms_output.put_line('Error message was: ' || SQLERRM);
7 END;
8 /
Exception, rolling back transaction, SP_AD not resolved.
Error message was: ORA-00911: invalid character
PL/SQL procedure successfully completed.
You can also use dbms_utility.format_error_backtrace to return the current stacktrace as a string, if you so wish. That might help you figure out where the error came from.
Alternatively, you can reraise the exception. Using RAISE on its own in an EXCEPTION handler reraises the current exception:
SQL> BEGIN
2 EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
3 EXCEPTION
4 WHEN OTHERS THEN
5 dbms_output.put_line('Exception, rolling back transaction, SP_AD not resolved.');
6 RAISE;
7 END;
8 /
Exception, rolling back transaction, SP_AD not resolved.
BEGIN
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 6
However, given the fact that your EXCEPTION handler isn't really doing anything helpful, the best approach is quite probably to get rid of it altogether.
Your exception handler doesn't achieve anything because you can't commit or rollback DDL statements such as CREATE, ALTER, DROP or TRUNCATE. Each of these statements issues a COMMIT immediately before and after it runs. If a DROP succeeds but a RENAME fails, you can't get the dropped table back by rolling back a transaction. I'd recommend getting rid of your COMMIT WORK and ROLLBACK WORK statements.
Finally, commenter Jeffrey Kemp noticed this line:
SELECT SOURCE INTO source FROM map_switch WHERE ROWNUM = 1;
This assigns into a variable named source the value of the column SOURCE from some arbitrary row of the table map_switch. It could be any row; as you haven't specified any ordering, Oracle is free to order the rows of map_switch however it likes.
If there's only one row in the table, then it's clear which row you'll get back. However, if this is the case, why specify ROWNUM = 1? Does the table have more than one row and is the ROWNUM = 1 part is just there to silence an 'exact fetch returns more than requested number of rows' error?
You would be better off doing something like the following:
SELECT SOURCE INTO source
FROM (SELECT SOURCE FROM map_switch ORDER BY some_column)
WHERE ROWNUM = 1;
I don't know what columns there are in your map_switch table, so I've just used some_column above as a placeholder for one of them. Choose a column that has unique values, if possible.
Note that we can't simply do SELECT ... WHERE ROWNUM = 1 ORDER BY some_column as that would apply the ROWNUM = 1 clause before doing the sorting, and there's not a lot of point sorting a single row as there's only one order it can be returned in.
Im trying to change the information on each row depending on the result from the query. Im thinking that at the minute my problem is that I'm only returning the first result from the query into the result.
e.g. query returns row 1 with '1232' row 2 '1243' but result is only ever set to '1232'
I could be wrong but its why I'm here :)
You say that your SQL returns multiple rows, but are using the ExecuteScalar() to run it. ExecuteScalar will only return a single result, ie the first column of the first row. Sounds like you need to fill a datatable using a SQLDataAdapter or something else to do what you're looking for.
Also it would be beneficial if you included your SQL statement as rlb indicated.