Trigger performing insert - sql

I have to create a trigger that does not allow more than one null in a certain column (hourfinish). Here is the trigger I wrote (I am using Sybase):
ALTER TRIGGER "InsertIntoCardDetail" instead of insert on
DBA.CardDetail
referencing new as new_name
for each row
begin
declare #nullCount integer;
if(new_name.hourfinish is null) then
select COUNT(*) into #nullCount
from CardDetail
where hourfinish is null;
if(#nullCount > 0) then
raiserror 99999 'Cannot have Multiple Nulls'
else
insert into CardDetail( card,hourstart,hourfinish,"work",project,N)
values( new_name.card,new_name.hourstart,new_name.hourfinish,new_name."work",new_name.project,new_name.N)
end if
else
insert into CardDetail( card,hourstart,hourfinish,"work",project,N)
values( new_name.card,new_name.hourstart,new_name.hourfinish,new_name."work",new_name.project,new_name.N)
end if
end
The trigger works fine. What I am asking is if there is a command executing the insert - a command that can replace those long insert statements.

Try to change your trigger to:
ALTER TRIGGER "InsertIntoCardDetail" instead of insert on
DBA.CardDetail
referencing new as new_name
for each row
begin
if(new_name.hourfinish is null) then
if exists
(select 1
from CardDetail
where hourfinish is null) then
raiserror 99999 'Cannot have Multiple Nulls'
return 1
end if --exists
end if--(new_name.hourfinish is null)
insert into CardDetail( card,hourstart,hourfinish,"work",project,N)
values(new_name.card,new_name.hourstart,new_name.hourfinish,new_name."work",new_name.project,new_name.N)
end

I achieved the same result with a before insert trigger. This way i don't need to write any insert statement in the trigger.
ALTER TRIGGER "InsertIntoCardDetail" before insert on
DBA.CardDetail
referencing new as new_name
for each row
begin
if(new_name.hourfinish is null)
and exists(select 1
from CardDetail
where hourfinish is null) then
raiserror 99999 'Cannot have Multiple Nulls'
end if;
end

Related

Trigger not ending execution or input

I have to check before inserting or updating a certain relation whether a particular row attribute in relation A is equal or greater than a corresponding row attribute in relation B. I wrote a trigger:
Attempt:
CREATE TRIGGER CandyCons AFTER INSERT, UPDATE ON Rel_A
AS
IF EXISTS (
SELECT * FROM Rel_A A, Rel_B B WHERE A.ID = B.ID AND A.candy > B.too_much
)
BEGIN
RAISERROR ('Stop eating!', 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END;
I can't execute this. When I run it, I start getting line numbers like:
query
12
13
14
15
......... and so on
What should I do?
This can be done with a row level TRIGGER as in the following example.
First create the tables:
CREATE TABLE REL_B(ID NUMBER NOT NULL PRIMARY KEY, TOO_MUCH NUMBER);
CREATE TABLE REL_A(ID NUMBER NOT NULL REFERENCES REL_B(ID), CANDY NUMBER);
Then add some test data:
INSERT INTO REL_B VALUES (1,10);
INSERT INTO REL_B VALUES (2,20);
COMMIT;
Then create your TRIGGER:
CREATE OR REPLACE TRIGGER CANDYCONS
AFTER INSERT OR UPDATE ON REL_A
FOR EACH ROW
DECLARE
V_COUNT_TOO_MUCH_CANDY NUMBER := 0;
BEGIN
SELECT COUNT(*) INTO V_COUNT_TOO_MUCH_CANDY
FROM REL_B
WHERE REL_B.ID = :NEW.ID
AND :NEW.CANDY > REL_B.TOO_MUCH;
IF (V_COUNT_TOO_MUCH_CANDY > 0)
THEN
RAISE_APPLICATION_ERROR(-20144,'Stop eating!');
END IF;
END;
/
Then test:
These are ok:
INSERT INTO REL_A VALUES (1,9);
INSERT INTO REL_A VALUES (1,10);
But this is blocked:
INSERT INTO REL_A VALUES (1,11);
Error starting at line : 1 in command -
INSERT INTO REL_A VALUES (1,11)
Error report -
ORA-20144: Stop eating!
On the line after END;, enter a single slash (/) to tell SQLPlus to execute the current command buffer.
See also When do I need to use a semicolon vs a slash in Oracle SQL?
(There may be other issues with your code, and the other answers may address them. But I believe this is your immediate problem in terms of actually telling SQLPlus to compile and create the trigger.)
I believe you intend this:
CREATE TRIGGER CandyCons ON Rel_A
BEFORE INSERT, UPDATE
AS
IF EXISTS (SELECT 1 FROM Rel_B B WHERE :NEW.ID = B.ID AND :NEW.candy > B.too_much
)
BEGIN
RAISERROR ('Stop eating!', 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END;
Wait. Oracle doesn't support if exists. And it requires then. So:
CREATE TRIGGER CandyCons ON Rel_A BEFORE INSERT, UPDATE
DECLARE
v_cnt number;
BEGIN
SELECT COUNT(*) INTO v_cnt
FROM Rebl_B B
WHERE :NEW.ID = B.ID AND :NEW.candy > B.too_much;
IF v_cnt = 0 THEN
BEGIN
RAISERROR ('Stop eating!', 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END;
END;

sql DELETE trigger won't rollback

The trigger is supposed to rollback if the statement in the SELECT exists. The thing is, it doesn't. When I only run the SELECT from the trigger, it shows that a row exists. But when I try DELETE with the same values as I have hard coded in the trigger, the trigger fires but it does not do a rollback. Anyone got any ideas what might be wrong?
CREATE TRIGGER trg_del ON Projektbefattningar
FOR DELETE
AS
SELECT #befNr = Befattningsnr, #pNr = pNr, #EtappNr = Etappnr FROM deleted
-- Not currently using these. Using hard coded values to illustrate my problem
IF EXISTS (
SELECT *
FROM projektbefattningar
WHERE Befattningsnr = 2 AND pNr = 1 and Etappnr = 1 AND Anställningsnr is not null
)
BEGIN
RAISERROR('Could not delete, Anställningsnr is not null', 16, 1)
--THROW 50001, 'Could not delete, Anställningsnr is not null', 1;
ROLLBACK TRANSACTION;
END
GO
When you use FOR DELETE you consider that this TRIGGER will fired after the delete statement is complete. To Verify a condition before DELETE you need to use INSTEAD OF DELETE. Your Trigger declaration will be:
CREATE TRIGGER trg_del ON Projektbefattningar
INSTEAD OF DELETE
AS
Now To Confirm your delete statement you need to include the delete alghouth it will not be deleted.
The final procedure will be like this:
CREATE TRIGGER trg_del ON Projektbefattningar
INSTEAD OF DELETE
AS
SELECT #befNr = Befattningsnr, #pNr = pNr, #EtappNr = Etappnr FROM deleted
-- Not currently using these. Using hard coded values to illustrate my problem
IF EXISTS (
SELECT *
FROM projektbefattningar
WHERE Befattningsnr = 2 AND pNr = 1 and Etappnr = 1 AND Anställningsnr is not null
)
BEGIN
RAISERROR('Could not delete, Anställningsnr is not null', 16, 1)
--THROW 50001, 'Could not delete, Anställningsnr is not null', 1;
ROLLBACK TRANSACTION;
END
ELSE
BEGIN
DELETE FROM YourTableToDelete Where idOfYourTable in ( Select idOfYourTable from Deleted )
END
GO
Try this
CREATE TRIGGER trg_del ON Projektbefattningar
FOR DELETE
AS
SELECT #befNr = Befattningsnr
,#pNr = pNr
,#EtappNr = Etappnr
FROM deleted
-- Not currently using these. Using hard coded values to illustrate my problem
IF EXISTS (
SELECT 1
FROM deleted
WHERE Befattningsnr = 2
AND pNr = 1
AND Etappnr = 1
AND Anställningsnr IS NOT NULL
)
BEGIN
RAISERROR (
'Could not delete, Anställningsnr is not null'
,16
,1
)
--THROW 50001, 'Could not delete, Anställningsnr is not null', 1;
ROLLBACK TRANSACTION;
END
GO

Transaction roll back not working in Postgresql

I am working on PostgreSQL 9.1.4 .
I am inserting the data into 2 tables its working nicely.
I wish to apply transaction for my tables both table exist in
same DB. If my 2nd table going fail on any moment that time my 1 st
table should be rollback.
I tried the properties in "max_prepared_transactions" to a non zero
value in /etc/postgres/postgres.conf. But Still Transaction roll
back is not working.
in postgresql you cannot write commit or roll back explicitly within a function.
I think you could have use a begin end block
just write it simple
BEGIN;
insert into tst_table values ('ABC');
Begin
insert into 2nd_table values ('ABC');
EXCEPTION
when your_exception then
ROLL BACK;
END;
END;
Probably you didn't started transaction.
Please, try
BEGIN;
INSERT INTO first_table VALUES(10);
-- second insert should fail
INSERT INTO second_table VALUES(10/0);
ROLLBACK;
I think it would be helpfull
create proc DataInsertInTable
as
begin tran
insert into Table1 values('Table1Data','XYZ')
if(##ERROR <>0)
begin
rollback tran;
return 0
end
insert into Table2 values('Table2Data','ABC')
if(##ERROR <>0)
begin
rollback tran;
return 0
end
commit Tran
return 1

Sql Server Triggers. How does the trigger checks for Update Command?

I have a trigger for auditing purchase and sales table. The trigger is on INSERT and DELETE. To check if its "Insert", the condition is
IF (SELECT COUNT(*) FROM INSERTED) > 0
BEGIN
END
How do I check if its an Update command inside the Trigger?
Arun
The "tables" that are in play in an update trigger are still called inserted and deleted, and the old values of the rows are in the deleted table, and the new values are in the inserted table.
You can use logic along these lines to detect whether you are in a insert, update or a delete:
CREATE TRIGGER MyTrigger
ON MyTable
AFTER INSERT,DELETE,UPDATE -- you need to add the "update" here,
-- in order to catch updates as well
AS
BEGIN
Declare #insertedCount int
Declare #deletedCount int
select #insertedCount = COUNT(*) from inserted
select #deletedCount = COUNT(*) from deleted
if (#insertedCount != 0) -- we have some new values
if (#deletedCount = 0) -- do we have old values?
print 'Inserting'
else
print 'Updating'
else
print 'Deleting'
END
An INSERT,DELETE trigger will not fire for updates.
.........................
CREATE an INSERT, UPDATE, DELETE all in one table
IF ##ROWCOUNT = 0
BEGIN
RETURN;
END;
IF EXISTS(SELECT * FROM inserted)
BEGIN
IF EXISTS(SELECT * FROM deleted)
BEGIN
-- for UPDATE
END
ELSE
BEGIN
-- for INSERT
END
END
ELSE
BEGIN
-- for DELETE
END;
Once you've updated your trigger (as Mitch says) to also apply to UPDATEs, you need to check for updates first:
IF EXISTS(select * from inserted) and EXISTS(select * from deleted)
BEGIN
--Update
END
Note that I've switch to EXISTS rather than COUNT(*). Exists more properly describes what we want to establish - that rows exist in the table. We don't care how many rows are in there.
I would like to thank "SWeko" for the clue.
Now, this what I did and the Trigger worked.
CREATE TRIGGER dbo.Sample
ON TableName
FOR INSERT, UPDATE, DELETE
AS
IF (SELECT COUNT(*) FROM INSERTED) > 0
BEGIN
IF (SELECT COUNT(*) FROM DELETED) > 0
BEGIN
-- UPDATE (TABLE).
END
ELSE
BEGIN
-- INSERT (TABLE).
END
END
ELSE
-- DELETE (TABLE).
BEGIN
END

Error on executing trigger

CREATE OR REPLACE TRIGGER PROCESS_POPULATE_INSTANCE
AFTER INSERT OR UPDATE ON PROCESS_INSTANCE
FOR EACH ROW
DECLARE
InstanceExists NUMBER;
BEGIN
SELECT COUNT(*)
INTO InstanceExists
FROM TEST_PROCESSDATA
WHERE TEST_PROCESSDATA.PROCESS_INSTANCE_ID = :NEW.INSTANCE_ID ;
IF ( InstanceExists > 0 ) THEN
UPDATE TEST_PROCESSDATA SET PROCESS_STATUS =:NEW.STATUS WHERE PROCESS_INSTANCE_ID = NEW.INSTANCE_ID;
ELSIF
INSERT INTO TEST_PROCESSDATA (PROCESS_INSTANCE_ID,PROCESS_STATUS, STARTED_TIME) VALUES (:NEW.INSTANCE_ID,:NEW.STATUS,:NEW.START_TIME);
END IF;
END PROCESS_POPULATE_APPDATA;
On executing the above trigger, i get the below error:
Error(12,2): PLS-00103: Encountered the symbol "INSERT" when expecting one of the following: ( - + case mod new not null continue avg count current exists max min prior sql
stddev sum variance execute forall merge time timestamp interval
date
pipe
Error(13,2): PLS-00103: Encountered the symbol "END"
In addition to what Ravindra bagale has already noted I would add the following:
First. In the statement
UPDATE TEST_PROCESSDATA SET PROCESS_STATUS =:NEW.STATUS
WHERE PROCESS_INSTANCE_ID = NEW.INSTANCE_ID;
: colon is missing in front of NEW.INSTANCE_ID
And second. You might consider using of merge statement instead of IF .. THEN .. ELSE.. END IF construct and additional select statement. For example.
create or replace trigger process_populate_instance
after insert or update on process_instance
for each row
begin
merge into test_processdata
using dual
on (process_instance_id = :new.instance_id)
when matched
then update
set process_status =:new.status
when not matched
then insert (process_instance_id,process_status, started_time)
values (:new.instance_id,:new.status,:new.start_time);
end;
use ELSE instead of ELSIF
here u used elseif,but not used else, u can't use elseif without else
when there are more than two way then u can use elsif.
IF ( InstanceExists > 0 ) THEN
UPDATE TEST_PROCESSDATA SET PROCESS_STATUS =:NEW.STATUS WHERE PROCESS_INSTANCE_ID = NEW.INSTANCE_ID;
ELSE
INSERT INTO TEST_PROCESSDATA (PROCESS_INSTANCE_ID,PROCESS_STATUS, STARTED_TIME) VALUES (:NEW.INSTANCE_ID,:NEW.STATUS,:NEW.START_TIME);
END IF;
END PROC