Oracle PL/SQL: What's missing in this trigger? - sql

I'm new to Triggers and PL/SQL in general. FOr testing purpose I'm using slely the Oracle Database Express Edition with its own Command Line.
The script supposed to create a trigger looks like follows:
CREATE OR REPLACE TRIGGER SESSION_LOGIN_HANDLER
AFTER UPDATE OF LOGGED_IN ON BENUTZERKONTO
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
BEGIN
if (:OLD.LOGGED_IN == 1)
if (:NEW.LOGGED_IN == 0)
{
UPDATE SESSION_LOGGING AS current_session SET DAUER = (sysdate-ZEITSTEMPEL) WHERE DAUER IS NULL AND SECURE_IDENTIFIER = :NEW.SECURE_IDENTIFIER;
}
END;
commit;
And I call it with #C:/SQL.../DB_TRIGGER.trg; in the command line.
Yet just after calling it, the command line seems just to count the line number with each time I press .
It seems like it somehow waits for another line or anything, but I don't know what ><
There's also no failure message or anything.
I even commented out the entire code between "BEGIN" and "END" with no difference!
Could someone help this beginner? Thanks in advance!

That's no Oracle syntax, it must be like this:
if (:OLD.LOGGED_IN = 1) then
if (:NEW.LOGGED_IN = 0) then
UPDATE SESSION_LOGGING AS current_session SET DAUER = (sysdate-ZEITSTEMPEL)
WHERE DAUER IS NULL AND SECURE_IDENTIFIER = :NEW.SECURE_IDENTIFIER;
end if;
end if;

Related

PL/SQL: ORA-00920: invalid relational operator

I get this error
23/112 PL/SQL: ORA-00920: invalid relational operator
It's pointing to AND CURRENT OF statement..
CREATE OR replace PROCEDURE alga_uz_pasirodyma(grupe_id in grupes.id%TYPE, alga in out number)
IS
v_kliento_id nariai.asm_kodas%TYPE;
TYPE bendras IS RECORD (
alga number
);
globalus bendras;
CURSOR c_klientai IS
SELECT nariai.asm_kodas
FROM nariai
where nariai.fk_grupe = grupe_id
FOR UPDATE OF nariai.alga;
BEGIN
globalus.alga:= alga;
IF grupe_id <= 0 THEN
raise_application_error(-20101, 'Nepavyko surasti grupes');
END IF;
OPEN c_klientai;
LOOP
FETCH c_klientai INTO v_kliento_id;
EXIT WHEN c_klientai%NOTFOUND;
UPDATE nariai set nariai.alga = nariai.alga * globalus.alga where nariai.asm_kodas = v_kliento_id AND CURRENT OF c_klientai;
END LOOP;
UPDATE grupes set grupes.pasirodymu_kiekis = grupes.pasirodymu_kiekis + 1 where grupes.id = grupe_id;
SELECT max(nariai.alga) into alga from nariai where nariai.fk_grupe = grupe_id;
CLOSE c_klientai;
END alga_uz_pasirodyma;
What should I do? I believe everything is declared correctly in the where statement..
"CURRENT OF" should be by itself in the where clause. It allows you to update or delete the record at the current loop iteration of the cursor.
On a different note, I don't see you doing anything significant in the loop to warrant a cursor. Ignore this note if that will change, otherwise just run the update "where nariai.fk_grupe = grupe_id"

UDF on DB2 11.0

I was asked to build a user defined function on our Mainframe environment that checks for a search string in a longer string. The only catch is that if we search for example for 'AA' in 'ABCAADAA' the only valid result is the last AA because the first AA actually split in CA and AD.
CREATE FUNCTION F#CRE#WK (WK CHAR(02), WKATTR CHAR(10))
RETURNS INTEGER
LANGUAGE SQL
READS SQL DATA
BEGIN
DECLARE INDEX INTEGER DEFAULT 1;
WHILE (INDEX < 9) DO
SET INDEX = LOCATE_IN_STRING(WKATTR, WK, INDEX);
IF (MOD(INDEX, 2) <> 0) THEN
RETURN 1;
END IF;
END WHILE;
RETURN 0;
END;
It is working fine when I implement it using Data Studio but if I put it onto the host directly (we're using Quick32770) I'm getting a bunch of errors which don't make sense at all. I couldn't find any helpful resources(searched the whole IBM page and Google of course).
First error I'm getting is:
SQLCODE = -104, ERROR: ILLEGAL SYMBOL "<END-OF-STATEMENT>". SOME
SYMBOLS THAT MIGHT BE LEGAL ARE: ;
Which refers to the line I'm declaring my index variable. If I remove the semicolon it tells me that the SET is illegal there because it is expecting a semicolon.
I cannot think of anything else I could try(I messed around with the code a lot but errors just kept getting more weird.). I started working in this field while being in college just a couple of weeks ago and nobody here has actual knowledge about this so I was hoping to find some help here.
If there's anything else you need, just let me know!
Thanks in advance.
This might help you:
https://bytes.com/topic/db2/answers/754686-db2-udf-need-eliminate-if-statement
It says the if statement is not allowed on the mainframe in UDF ?
So this user bend it around to a CASE function.
In order to fix this you need to go into the SPUFI settings and change the TERMINATOR option to something else than a semicolon. If I changed it to & my code must look like this:
CREATE FUNCTION F#CRE#WK (WK CHAR(02), WKATTR CHAR(10))
RETURNS INTEGER
LANGUAGE SQL
READS SQL DATA
BEGIN
DECLARE INDEX INTEGER DEFAULT 1;
WHILE (INDEX < 9) DO
SET INDEX = LOCATE_IN_STRING(WKATTR, WK, INDEX);
IF (MOD(INDEX, 2) <> 0) THEN
RETURN 1;
END IF;
END WHILE;
RETURN 0;
END&

PL/SQL ORA06550 error in an update statement

The following is a proc code that I have written . I am getting a syntax error in the block marked from (A) to (B) , namely , ORA06550, saying SQL command not ended properly.
If I eliminate the line l.ban4_upd ='UPDATED' there are no more of nay error messages.
I don't know how to correct it . Hoping for your help and thanks in advance
DECLARE
dummy_BAN4 VARCHAR2(30);
dummy_bank_acc_num VARCHAR2(20);
CURSOR c_customers is
SELECT BAN4,Bank_acc_num FROM Test_Table ;
BEGIN
OPEN c_customers;
LOOP
FETCH c_customers into dummy_BAN4 , dummy_bank_acc_num;
IF c_customers%notfound THEN
update Test_Table chs Set
chs.error_msg ='No such record found in DB '
where bank_acc_num =dummy_bank_acc_num;
END IF;
update Transact_ord2 l Set.........................(A)
l.ban4_upd ='UPDATED'
l.x_account_number =dummy_BAN4
where X_account_number =dummy_bank_acc_num; ..........(B)
you are missing , between the fields you set:
update Transact_ord2
Set ban4_upd = 'UPDATED',
x_account_number = dummy_BAN4
where X_account_number = dummy_bank_acc_num;
Check this

DB2 Procedures return result set after for loop

I'm currently on writing a SQL-Procedure on IBM i 5 V7R1.
If I want to return a result set after my for loop I can't create the procedure.
Here is the code:
create or replace procedure test1()
DYNAMIC RESULT SETS 1
LANGUAGE SQL
SPECIFIC EDVVAEH1.test1
NOT DETERMINISTIC
MODIFIES SQL DATA
CALLED ON NULL INPUT
SET OPTION ALWBLK = *ALLREAD ,
ALWCPYDTA = *OPTIMIZE ,
COMMIT = *NONE ,
DECRESULT = (31, 31, 00) ,
DFTRDBCOL = *NONE ,
DYNDFTCOL = *NO ,
DYNUSRPRF = *USER ,
SRTSEQ = *HEX
proc: BEGIN
DECLARE x VARCHAR(255);
DECLARE return_cur CURSOR with return FOR
select * from sysibm.sysdummy1;
loop1: for record as C1 cursor for
SELECT TABLE_NAME
from qsys2.systables
DO
SET x = record.table_name;
END FOR loop1;
open return_cur;
END proc
As the options define, I want to return a result set after both loops, but it doesn't let me create this procedure.
The Error is -104 token: "End of Statement" is not valid, but everything is there :(
It seems I found the root cause of my problem, but I can't fix it.
As far as I can see, my i Access has a Problem with the for-statement.
I copied the statement to my RDi 9.1 in the Database Development view and ran it there. I also set a different end of statement command and after that I was able to create my procedure.
Now I need to wait until someone in my company can provide me a PTF for the client access. I already tried to install all PTFs delivered with the IBM i, but no improvements ...
If anyone has an idea, where I can download a PTF for client Access please give me a hint. The IBM site is not possible for me since, I am not registered for out IBM i.
Thanks.

Oracle UPDATE has no effect

I am working on Sql Developper an I created the following procedure in a package:
PROCEDURE VALIDER(a_session IN NUMBER) AS
i NUMBER;
TYPE type_tab IS TABLE OF PANIER%ROWTYPE;
tabSeances type_tab;
BEGIN
SELECT * BULK COLLECT INTO tabSeances
FROM PANIER
WHERE a_session = sessionweb;
i:=0;
FOR i IN 1 .. tabSeances.count LOOP
-- UPADTE DU NOMBRE DE PLACES LIBRES
BEGIN
UPDATE PROJECTION
SET remaining_seats = (remaining_seats - tabseances(i).nbrplaces)
WHERE num_copy = tabseances(i).num_copy
AND day = tabseances(i).dateseance
AND time_slot = tabseances(i).time_slot
AND movie = tabseances(i).movie;
COMMIT;
--UPDATE ON PANIER
UPDATE PANIER
SET valide = 1
WHERE sessionweb = a_session
AND num_copy = tabseances(i).num_copy
AND dateseance = tabseances(i).dateseance
AND time_slot = tabseances(i).time_slot
AND movie = tabseances(i).movie;
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN raise_application_error(-20035, 'Pas de données');
WHEN OTHERS THEN raise_application_error(-20006,'Autres Erreurs');
END;
END LOOP;
END VALIDER;
The procedure executes normaly and I don't get an error.
I have a kind of product cart: "PANIER". I loop all the entries in thsi cart for one person (session) to validate them in the database and decrement the total number of seats.
But the field "remaining-seats" (from PROJECTIONS) in the first update don't work. The field isn't updated. I have already tried with other values but nothing.
I am sure that the procedure is executetd because the second update still works. It marks the cart entry as "CONFIRMED".
I don't have any trigger on this field.
My tables contains valid data (<>NULL).
I execute this procedure like this (in a BEGIN END; block):
CMDPLACES.VALIDER(1);
Thank for your reply.
Is it day or dateseance in your first update?
UPDATE PROJECTION
SET remaining_seats = (remaining_seats - tabseances(i).nbrplaces)
WHERE num_copy = tabseances(i).num_copy
AND dateseance = tabseances(i).dateseance
AND time_slot = tabseances(i).time_slot
AND movie = tabseances(i).movie;
Also as #ThorstenKettner was mentioning, the timestamp data in the date , may fail while comparing, so we have TRUNCATE the timestamp data using TRUNC() [if needed]!
If the date column is indexed, beware the index will not be used by the database .
To handle NO Data in UPDATE, you can check (SQL%ROWCOUNT > 0) to identify the number of rows updated!
Your first update compares days. What data type are these? In case you deal with DATETIME, make sure to compare without the time part if any. Use TRUNC to achieve this.
AND TRUNC(day) = TRUNC(tabseances(i).dateseance)