How to create a trigger before insert in db2 - triggers

I have three tables below:
I need to create a trigger to disallow students to take a class without completing their pre-requisites (must use a trigger). The trigger must return an error message "Missing Pre-req" when trying to insert a class without its proper pre-req.
So far, I wrote a command below:
create trigger checkPrereq
before insert on HW3.SCHEDULE
referencing new as newRow
for each row
When
(
select GRADE
from HW3.SCHEDULE
where HW3.SCHEDULE.ClassId =
(
select PrereqId from HW3.CLASS_PREREQ
where newRow.ClassId = HW3.CLASS_PREREQ.ClassId
)
) in ('F', null)
begin atomic
set newRow.Semester = null;
signal sqlstate 'KILLED' set message_text = ('Missing Pre-req');
end
but I got a warning:
DB21034E The command was processed as an SQL statement because it was
not a valid Command Line Processor command. During SQL processing it
returned: SQL0104N An unexpected token "GRADE" was found following
"ach row When (select". Expected tokens may include: ")". LINE
NUMBER=1. SQLSTATE=42601
I can not understand what was happening here. Could you please help fix this? Any help is appreciated!

Related

Create History Trigger Db2

I am trying to create a trigger that copys a newly INSERTED and/or UPDATED record from one table to a History version of this table. The purpose is to keep a record every time a record in a table is inserted and/or updated.
This is the Create Trigger statement syntax that I have, following the IBM Db2 Trigger site.
CREATE TRIGGER "TADB2"."HIST_CSEMASTER_Z_LOG"
AFTER UPDATE ON TADB2.CSEMASTER_Z
REFERENCING NEW AS N
FOR EACH ROW
BEGIN ATOMIC
INSERT INTO TADB2.HIST_CSEMASTER_Z
values (N.CSEMASTERID, N.CURRID, N.SUBCURRID, N.EXPIREDATE, N.CREATEDATE, N.CUSTVIEWNUM, N.CSEMSTRNAME, N.JOINCODE, N.CONTACTCOUNTRYCD, N.CONTACTSERIALNUM, N.AUDIENCECD, N.SPONSORNAME, N.AVAILABLEDATE, N.OWNERCOUNTRYCD, N.OWNERSERIALNUM, N.PRMWWCHAPTERID, N.PRMWWSUBCHAPTERID, N.SECWWCHAPTERID, N.SECWWSUBCHAPTERID, N.INTRANETIND, N.TINSERTTS, N.TLASTUPDTS, N.IBM_TRADEMARK, N.OTHER_TRADEMARK, N.INTERNETIND, N.BRANDID, N.BUSINESSID, N.LIFECYCLE_STATUS);
END;
The error I am receiving is:
[Code: -104, SQL State: 42601] An unexpected token "END-OF-STATEMENT" was found following "N.LIFECYCLE_STATUS)". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=3.72.44
I've tried:
Removing the END
Removing the semi-colon after the END
Removing the semi-colon after the N.LIFECYCLE_STATUS);
Any help would be great! Thank you.
I highly recommend Db2 Temporal Tables for that. If you just use System Temporal functionality it would provide already the functionality you describe.
Worth to check it out
You must use different from ';' statement terminator in your tool.
Below is an example for DB2 Command Line Processor, which understands the first line as a directive to do this.
--#SET TERMINATOR #
CREATE TRIGGER "TADB2"."HIST_CSEMASTER_Z_LOG"
AFTER UPDATE ON TADB2.CSEMASTER_Z
REFERENCING NEW AS N
FOR EACH ROW
BEGIN ATOMIC
INSERT INTO TADB2.HIST_CSEMASTER_Z
values (N.CSEMASTERID, N.CURRID, N.SUBCURRID, N.EXPIREDATE, N.CREATEDATE, N.CUSTVIEWNUM, N.CSEMSTRNAME, N.JOINCODE, N.CONTACTCOUNTRYCD, N.CONTACTSERIALNUM, N.AUDIENCECD, N.SPONSORNAME, N.AVAILABLEDATE, N.OWNERCOUNTRYCD, N.OWNERSERIALNUM, N.PRMWWCHAPTERID, N.PRMWWSUBCHAPTERID, N.SECWWCHAPTERID, N.SECWWSUBCHAPTERID, N.INTRANETIND, N.TINSERTTS, N.TLASTUPDTS, N.IBM_TRADEMARK, N.OTHER_TRADEMARK, N.INTERNETIND, N.BRANDID, N.BUSINESSID, N.LIFECYCLE_STATUS);
END#

How to return values from dynamically generated "insert" command?

I have a stored procedure that performs inserts and updates in the tables. The need to create it was to try to centralize all the scan functions before inserting or updating records. Today the need arose to return the value of the field ID of the table so that my application can locate the registry and perform other stored procedures.
Stored procedure
SET TERM ^ ;
CREATE OR ALTER procedure sp_insupd (
iaction varchar(3),
iusuario varchar(20),
iip varchar(15),
imodulo varchar(30),
ifieldsvalues varchar(2000),
iwhere varchar(1000),
idesclogs varchar(200))
returns (
oid integer)
as
declare variable vdesc varchar(10000);
begin
if (iaction = 'ins') then
begin
vdesc = idesclogs;
/*** the error is on the line below ***/
execute statement 'insert into '||:imodulo||' '||:ifieldsvalues||' returning ID into '||:oid||';';
end else
if (iaction = 'upd') then
begin
execute statement 'select '||:idesclogs||' from '||:imodulo||' where '||:iwhere into :vdesc;
execute statement 'execute procedure SP_CREATE_AUDIT('''||:imodulo||''');';
execute statement 'update '||:imodulo||' set '||:ifieldsvalues||' where '||:iwhere||';';
end
insert into LOGS(USUARIO, IP, MODULO, TIPO, DESCRICAO) values (
:iusuario, :iip, :imodulo, (case :iaction when 'ins' then 1 when 'upd' then 2 end), :vdesc);
end^
SET TERM ; ^
The error in the above line is occurring due to syntax error. The procedure is compiled normally, that is, the error does not happen in the compilation, since the line in question is executed through the "execute statement". When there was no need to return the value of the ID field, the procedure worked normally with the line like this:
...
execute statement 'insert into '||:imodulo||' '||:ifieldsvalues||';';
...
What would be the correct way for the value of the ID field to be stored in the OID variable?
What is REAL VALUE in ifieldsvalues ?
you can not have BOTH
'insert into '||:imodulo||' '||:ifieldsvalues
'update '||:imodulo||' set '||:ifieldsvalues
because methods to specify column names and column values in INSERT and UPDATE statements is fundamentally different!!! You either would have broken update-stmt or broken insert-stmt!
The error in the above line is occurring due to syntax error
This is not enough. Show the real error text, all of it.
It includes the actual command you generate and it seems you had generated it really wrong way.
all the scan functions before inserting or updating records
Move those functions out of the SQL server and into your application server.
Then you would not have to make insert/update in that "strings splicing" way, which is VERY fragile and "SQL injection" friendly. You stepped into the road to hell here.
the error does not happen in the compilation
Exactly. And that is only for starters. You are removing all the safety checks that should had helped you in applications development.
http://searchsoftwarequality.techtarget.com/definition/3-tier-application
https://en.wikipedia.org/wiki/Multitier_architecture#Three-tier_architecture
http://bobby-tables.com
On modern Firebird versions EXECUTE STATEMENT command can have the same INTO clause as PSQL SELECT command.
https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-psql-coding.html#fblangref25-psql-execstmt
Use http://translate.ru to read http://www.firebirdsql.su/doku.php?id=execute_statement
Or just see SQL examples there. Notice, however, those examples all use SELECT dynamic command, not INSERT. So I am not sure it would work that way.
This works in Firebird 2.5 (but not in Firebird 2.1) PSQL blocks.
execute statement 'insert into Z(payload) values(2) returning id' into :i;
To run it from IBExpert/FlameRobin/iSQL interactive shell add that obvious boilerplate:
execute block returns (i integer) as
begin
execute statement 'insert into Z(payload) values(2) returning id' into :i;
suspend;
end

How to create a trigger in PostgreSQL without delegating control to a function?

I'm familiar with the method where the trigger is fired by a function:
CREATE TRIGGER mytrigger
BEFORE UPDATE ON mytable
FOR EACH ROW EXECUTE PROCEDURE some_function();
I would like to know if there is a way to now eliminate the need for the function. Something like this doesn't seem to work:
CREATE TRIGGER mytrigger
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
SET NEW.col1 = OLD.col1 + 1
END
The error I keep getting is: ERROR: syntax error at or near "BEGIN"
If I get rid of BEGIN and END, it says: ERROR: syntax error at or near "SET"
Other variations fail as well. For example:
CREATE TRIGGER mytrigger
BEFORE UPDATE ON mytable
FOR EACH ROW
UPDATE mytable SET col1 = OLD.col1 + 1;
Can this be done now? I'm currently using v9.4.
You can't do it, it simply isn't supported. That's why it isn't working.
You must use trigger functions in PostgreSQL. You can't just write some SQL in-line in the trigger.

"No current record for fetch operation" for select insert

Can anyone see why I'm getting the "No current record for fetch operation" below?
I'm successfully skipping duplicate records by catching and not re-throwing the unique key violation exception below. There is another error however.
FOR SELECT
...
FROM
P_SELECT_CLAIM_FILE cf
ORDER BY
cf.DATESBM, cf.TIMESBM, cf.TRANSCDE
INTO
...variables
DO BEGIN
INSERT INTO
CLAIM_TABLE (...)
VALUES (...variables);
WHEN GDSCODE unique_key_violation DO
TX_ID=0;
WHEN GDSCODE no_cur_rec DO
/* Why does this happen?
-508 335544348 no_cur_rec No current record for fetch operation
*/
EXCEPTION E 'no_cur_rec ' || TX_ID;
END
The procedure P_SELECT_CLAIM_FILE contains another FOR SELECT INTO with lots of trimming and finally a SUSPEND command. This reads from a fixed width text file.
I'm tempted to change this into a single INSERT SELECT where not exists statement. I prefer to make a minimal fix instead however; the holidays already here.

An unexpected token "CREATE TRIGGER

CREATE TRIGGER TRG_EFMREFNO
BEFORE
INSERT ON FEEDBACK_CASE_TB
FOR EACH ROW
BEGIN
SELECT SEQ_EFMREFNO.NEXTVAL INTO:NEW.EFMREFNO FROM DUAL;
END;
please help me it's give errors
An unexpected token "CREATE TRIGGER TRG_EFMREFNO
BEFOR" was found following "BEGIN-OF-STATEMENT". Expected tokens may include: "<revoke>".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.12.79
An unexpected token "END-OF-STATEMENT" was found following "END". Expected tokens may include: "JOIN <joined_table>".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.12.79
Please give the solution for that errors
You have 2 things going on here -
1) When the ";" character is part of the SQL statement, it's necessary to use a different character to terminate the statement. I typically use "#". To tell the "db2" command that you have chosen a different character, use
db2 -td#
or if you want to read from a file
db2 -td# -f <somefile>
2) The correct way to update new row in a trigger is to set an alias for the new row, and use a set clause:
CREATE TRIGGER TRG_EFMREFNO
BEFORE
INSERT ON FEEDBACK_CASE_TB
REFERENCING NEW AS N
FOR EACH ROW
BEGIN
SET N.EFMREFNO = SEQ_EFMREFNO.NEXTVAL;
END
#
There may be other ways to use the sequence with the default clause in the create table statement that will accomplish the same thing: