use insert value as trigger - sql

is it possible to use the insert value in the where clause in SQL?
I would want to use it in this kinda way:
create trigger t_wage_not_higher_than_30000
on transaction
as
if exists
(
select *
from transaction
where ***inserted value*** >= 30000 and
description = employeewage
)
begin
raiserror('you cannot insert a wage higher than 30000')
rollback transaction
end

If you want to check the range of values, the best way is to use a check constraint:
alter table transactions add constraint chk_transactions_value
check (value < 30000);
There is no reason to write a trigger for checking data values.

For this trigger, you should only refer to the newly inserted rows. Therefore, you need to use the special trigger table in your statement. E.g.,
if exists (select * from inserted
where <some column you did not name in
your code> >= 30000 and description = 'employeewage')
begin
raiserror ... (or throw);
rollback tran;
return;
end;
And yes - a constraint is generally a better approach.

Related

How to use multiple triggers?

DROP TRIGGER IF EXISTS N2Trigger
CREATE TRIGGER N2Trigger
ON dbo.Date
FOR INSERT, DELETE
AS
BEGIN
SELECT 'Inserted Datebase' as MESSAGE
SELECT 'Deleted Database' as MESSAGE
END
DELETE FROM dbo.[Date] WHERE ID = 1
Here is my code I just want when I use insert statement return 'Inserted Datebase' as MESSAGE
When I use delete statement return 'Deleted Database' as MESSAGE
The easiest way to check what action fired the trigger is to inspect the inserted and deleted pseudo-tables. If the trigger is only on DELETE/INSERT and not on update, then the logic is simply:
CREATE TRIGGER dbo.trFlarb ON dbo.flarb
FOR INSERT, DELETE
AS
BEGIN
IF EXISTS (SELECT 1 FROM inserted)
BEGIN
SELECT 'Inserted.';
END
IF EXISTS (SELECT 1 FROM deleted)
BEGIN
SELECT 'Deleted.';
END
END
Example db<>fiddle
Now, of course, Marc is right: triggers aren't for returning or printing output. This is just a demonstration that you can use those checks to then perform whatever logic you need to perform in the event of either action.
That said, if you have two distinctly different things you want to do depending on whether it's an insert or a delete, why not just create two separate triggers?
CREATE TRIGGER dbo.tr_I_Flarb ON dbo.flarb
FOR INSERT
AS
BEGIN
SELECT 'Inserted.';
END
GO
CREATE TRIGGER dbo.tr_D_Flarb ON dbo.flarb
FOR DELETE
AS
BEGIN
SELECT 'Deleted.';
END
GO
Note that SELECT will only "work" on your system if you haven't turned on the disallow results from triggers Server Configuration Option. Again, you should try to explain what you really want to do in the event of an insert or update, because the end goal can't be to print or return "Inserted" or "Deleted."

How to substitute a variable when creating a check constraint?

I need to add a required field for newly added rows. However, it is undesirable to set the default value for old rows due to the large size of the table. I need to provide an automated script that will do this.
I tried this, but it does not work:
do $$
declare
max_id int8;
begin
select max(id) into max_id from transactions;
alter table transactions add constraint check_process_is_assigned check (id <= max_id or process_id is not null);
end $$;
Utility commands like ALTER TABLE do not accept parameters. Only the basic DML commands SELECT, INSERT, UPDATE, DELETE do.
See:
set "VALID UNTIL" value with a calculated timestamp
“ERROR: there is no parameter $1” in “EXECUTE .. USING ..;” statement in plpgsql
Creating user with password from variables in anonymous block
You need dynamic SQL like:
DO
$do$
BEGIN
EXECUTE format(
'ALTER TABLE transactions
ADD CONSTRAINT check_process_is_assigned CHECK (id <= %s OR process_id IS NOT NULL)'
, (SELECT max(id) FROM transactions)
);
END
$do$;
db<>fiddle here
This creates a CHECK constraint based on the current maximum id.
Maybe a NOT VALID constraint would serve better? That is not checked against existing rows:
ALTER TABLE transactions
ADD CONSTRAINT check_process_is_assigned CHECK (process_id IS NOT NULL) NOT VALID;
But you do have to "fix" old rows that get updated in this case. (I.e. assign a value to process_id if it was NULL so far.) See:
Enforce NOT NULL for set of columns with a CHECK constraint only for new rows
Best way to populate a new column in a large table?

SQL IF statements in transactions

I'm trying to make a condition where if the number of available seats within a given plane is less than zero then ROLLBACK. However, I am receiving a message stating that there is a syntax error at IF (i.e. "syntax error at or near "IF""). Why is this, can I not use if statements in transactions? And if so, how can I perform this conditional statement?
BEGIN;
UPDATE FlightBooking SET NumSeats = NumSeats + 100, TotalCost = TotalCost + 100
WHERE CustomerID = 20005;
IF (SELECT Available_Seats FROM checkAvailability(30001) < 0) THEN
ROLLBACK;
END IF;
COMMIT;
Many thanks, callum
Use a check constraint!
alter table flightbooking add constraint chk_flightbooking_availability
check (availability >= 0);
That way, the update simply fails and the data never fails to meet your condition.
Alas, if you want to use your function, you need to convert it to a scalar value:
alter table flightbooking add constraint chk_flightbooking_availability
check (checkAvailability_scalar(30001) >= 0);
That said, it is probably better to store that value somewhere and use a check constraint on that table.
Personally I would do the check before the update... that way you don't have to roll back.
Here is how to fix your if statement.
IF (SELECT Available_Seats FROM checkAvailability(30001)) < 0 THEN
ROLLBACK;
END IF;

Values of the inserted row in a Trigger Oracle

I want a trigger that updates the value of a column, but I just want to update a small set of rows that depends of the values of the inserted row.
My trigger is:
CREATE OR REPLACE TRIGGER example
AFTER INSERT ON table1
FOR EACH ROW
BEGIN
UPDATE table1 t
SET column2 = 3
WHERE t.column1 = :new.column1;
END;
/
But as I using FOR EACH ROW I have a problem when I try it, I get the mutating table runtime error.
Other option is not to set the FOR EACH ROW, but if I do this, I dont know the inserted "column1" for comparing (or I dont know how to known it).
What can I do for UPDATING a set of rows that depends of the last inserted row?
I am using Oracle 9.
You should avoid the DML statements on the same table as defined in a trigger. Use before DML to change values of the current table.
create or replace trigger example
before insert on table1
for each row
begin
:new.column2 := 3;
end;
/
You can modify the same table with pragma autonomous_transaction:
create or replace trigger example
after insert on table1 for each row
declare
procedure setValues(key number) is
pragma autonomous_transaction;
begin
update table1 t
set column2 = 3
where t.column1 = key
;
end setValues;
begin
setValues(:new.column1);
end;
/
But I suggest you follow #GordonLinoff answere to your question - it's a bad idea to modify the same table in the trigger body.
See also here
If you need to update multiple rows in table1 when you are updating one row, then you would seem to have a problem with the data model.
This need suggests that you need a separate table with one row per column1. You can then fetch the value in that table using join. The trigger will then be updating another table, so there will be no mutation problem.
`create table A
(
a INTEGER,
b CHAR(10)
);
create table B
(
b CHAR (10),
d INTEGER
);
create trigger trig1
AFTER INSERT ON A
REFERENCING NEW AS newROW
FOR EACH ROW
when(newROW.a<=10)
BEGIN
INSERT into B values(:newROW.b,:newROW.a);
END trig1;
insert into A values(11,'Gananjay');
insert into A values(5,'Hritik');
select * from A;
select * from B;`

need to write a trigger

I want to write a trigger for a table "TRANSACTION".When a new line is inserted, I want to trigger to update the field "TRANSACTIONID" to the maximum + 1 of all the previous records.
I on't know much about SQL. Can someone help me?
many thanks
This is a really bad idea for a multi-user environment, as it will serialise inserts into the table. The usual approach is to use an Oracle sequence:
create sequence transaction_seq;
create trigger transaction_bir before insert on transaction
for each row
begin
:new.id := transaction_seq.nextval;
end;
To write a trigger based solution that actually got the max current value plus 1, you would need to write a complex 3-trigger solution to avoid the "mutating table" issue. Or you could create a simpler solution using another table to hold the current maximum value like this:
create table transaction_max (current_max_id number);
insert into transaction_max values (0);
create trigger transaction_bir before insert on transaction
for each row
declare
l_current_max_id number;
begin
update transaction_max set current_max_id = current_max_id + 1
returning current_max_id into l_current_max_id;
:new.id := l_current_max_id;
end;
This will avoid the mutating table issue and will serialize (slow down) inserts, so I don't see any advantage of this over using a sequence.
CREATE TRIGGER trigger1 on TransactionTable
INSTEAD OF INSERT
AS
BEGIN
DECLARE #MaxTranId INT
SELECT
#MaxTranId = MAX(TransactionId)
FROM
TransactionTable
INSERT INTO TransactionTable
SELECT
#MaxTranId + 1 ,
RestOfYourInsertedColumnsHere ,
FROM
inserted
END
GO