I am new to sql and i have an employee table. I want to create a trigger so that no one can insert a new employee record with salary less than 200. I tried this code but it doesn't accept any record anymore and i see this error "The transaction ended in the trigger. The batch has been aborted." whatever the salary is.
This is my code
Create trigger Trig on Employees after insert
As
Begin
if((Select count(EID) from inserted where salary<200)>0)
Rollback
else
Commit
End
Thanks in advance
For your scenario trigger is not a good solution. try to add check constraint on Salary column. I think Check constraint is a good solution for your problem
ALTER TABLE Employees
ADD CONSTRAINT chk_Salary CHECK (Salary>=200)
https://msdn.microsoft.com/en-us/library/ms187550.aspx
When using rollback, it will treat the entire transaction as one, so if one of the inserts within the trigger meets the condition, it will unfortunately rollback all of the inserts within the transaction.
So, basically if you want to have it work this way, you won't be able to use rollback as an option or it will delete all of the other salaries from this transaction.
Here's the workaround, when one of the items meets the condition that you don't want after the insert, you will need to do something like this:
BEGIN
IF ...
DELETE FROM Table WHERE …
END
Related
In SQL Server, I'm creating a backup table using the query below, this gives me an copy of the table Original named Backup:
select *
into Backup
from Original
How can I use my Backup table to restore all data to the Original (including id's)?
The original table contains ~20 columns and have 1 or more foreign keys pointing at its id.
Some entries from the Original may have been deleted, no new entries have been added.
I where thinking about doing something like:
TRUNCATE TABLE Original
SET IDENTITY_INSERT Original ON;
INSERT INTO Original (id, val1, val2,....)
SELECT id, val1, val2,....
FROM Backup;
SET IDENTITY_INSERT Original OFF;
but I can't truncate a table being referenced by a foreign key, and without emptying the table, the INSERT can run in to duplicated id's
Can someone help me with this?
As I mentioned, this is an XY Problem. What you think you want to do, and what you really need to do are completely different. YOu have described Y to us, but actually you want to do X.
This answer is based on your comment below:
From a program I need to delete a subset of them (around 100k) then preform some other operation, these can fail. If these operations fail i need to restore the deleted rows. I don't necessary want to delete all of them, I just need to put the rows that where deleted back in to the Original table, from the Backup table.
This is a trivial thing to do in SQL Server, you just need to use transactions. In very simple psuedo-SQL terms:
BEGIN TRY
BEGIN TRANSACTION DoWork;
--Do your logic here
--Do you need to also ROLLBACK under some scenario?
IF {Some Boolean Logic}
ROLLBACK TRANSACTION DoWork;
ELSE
COMMIT TRANSACTION DoWork;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION DoWork;
THROW;
END CATCH;
I made a trigger that is supposed to update another value in the same table a after I make an insert to the table. I do get the result I am looking for, but when I ask my teacher if it is correct he responded that this trigger updates "all" tables(?) and thus incorrect. He would not explain more than that (he is that kind of teacher...). Can anyone understand what he means? Not looking for the right code, just an explanation of what I might have misunderstood.
CREATE TRIGGER setDate
ON Loans
AFTER INSERT
AS
BEGIN
UPDATE Loans
set date = GETDATE()
END;
Your teacher intends to say that the query updates all rows in the table -- perhaps you misunderstood her or him.
The best way to do what you want is to use a default value:
alter table loans alter column date datetime default getdate();
That is, a trigger is not needed. If you did use a trigger, I'll give you two hints:
An instead of trigger.
inserted should be somewhere in the trigger.
Hello there. I upvoted your question because that might be the question of many beginners in SQL Server.
As I see you defined the trigger right! It is a correct way although it's not the best.
By the way we are not discussing all ways you could choose or not, I'm gonna correct your code and explain what your teacher meant.
Look at this UPDATE you wrote:
UPDATE Loans
SET date = GETDATE()
If you write a SELECT without a WHERE clause, what does it do? It would result all the rows in the table which was selected. right?
SELECT * FROM dbo.loans
So without a WHERE clause, your UPDATE will update all of the rows in the table.
OK now what to do to just update the only row ( or rows) which were recently inserted?
When you are writing a trigger, you are allowed to use this table: Inserted
which it has the rows were recently inserted. kinda these rows first come to this table and then go to the final destination table. So you can update them before they go the dbo.loans
it would be like this:
Update dbo.loans
SET date = GETDATE()
WHERE Id IN (SELECT * FROM Inserted)
I have the table "log" in an SQLite database, where I write all my log files.
However I want to pretend the database from getting to big - and the smartest way in doing this, is by using a trigger on the insert command - at least I think so...
When a new record is inserted, a trigger shall get fired, that deletes all records older than 10 days.
Or...
When a new record is inserted, a trigger shall get fired, that deletes all old records, which exceed a specific amount (for example 1000).
I need an example code.
Kind Regards, and thx.
This will create an insert trigger that will delete anything with a create date that is more then 10 days old.
CREATE TRIGGER [TRIGGER_NAME] AFTER INSERT ON my_table
BEGIN
DELETE FROM LOG WHERE DATE(CREATE_DATE) > DATE('now', '-10 days');
END
If you want to do something based on size like you were saying with 1000 rows you can do something like this.
CREATE TRIGGER [TRIGGER_NAME] AFTER INSERT ON my_table
BEGIN
DELETE FROM LOG WHERE ROW_NO NOT IN
(SELECT TOP 1000 ROW_NO FROM LOG ORDER BY CREATE_DATE DESC);
END
This will select the 1000 newest rows and delete anything that is not in that select statement.
EDIT: I don't know what distro it is, it's in an exam paper.
I'm just not getting this, sadly. I'm quite happy with Row level triggers but could someone explain to me how the results would differ if the trigger was statement level instead?
Relation/Statement Trigger/Row Level Trigger
Employee(ID VARCHAR2(30), Salary NUMBER)
Create Trigger AutoRaise
After insert on Employee
Referencing new table as NT
update Employee
Set salary = salary + (select avg(salary) from NT)
Create trigger AutoRaise
After insert on Employee
Referencing new table as NT
For each Row
Update employee
Set salary = salary + (select avg(salary) from NT)
I understand that in the for each row trigger it'll fire for each row affected by the triggering statement. Now would the statement level trigger modify the results differently? Say if I inserted five tuples in one statement, would it set the salary etc for them all? If so, what's the benefit of the row level trigger here?
I've tried searching but I just can't get my head around it.
Thanks,
EDIT: Now, I'm just being dense but would either trigger produce different outputs? For the statement level trigger if I used the example values:
In table before trigger's creation:
(A,50)
Added in ONE statement after trigger is created:
(B,70), (C,30)
The first trigger would set the salary for each tuple being inserted, surely? So the first would become 120 (as the average is 50, 70 + 50 = 120) and the second would become 80. If this is true, how does the second trigger differ in results?
The difference is that in case of statement level trigger SELECT avg(salary) FROM NT will return average of salary for inserted rows, but in case of row level, avg(salary) always equals to salary of new record (trigger executed for each row individually). Also, statement level trigger will be executed if no records affected. In case of row level trigger most RDMS don't fire it when 0 records affected.
Side note. I believe the trigger bodies in the question are given for example only; otherwise, I'd recommend not using recursion in triggers even if particular RDMS has such an option.
I need to write a trigger that only runs when an insertion that has a certain field with a specific value is inserted. There is no updating.
For example, if I insert an entry that has column X with the value "MAC ID", I want it to run a trigger, but ONLY if the value is "MAC ID".
I know how to test for this normally, but not sure how to test this in a trigger. So far I've found that I want to use "FOR INSERT", but beyond that I don't know how to implement it.
Any help is much appreciated! Thanks!
create trigger MaxIdInsert
on YourTable
after insert
as
if exists
(
select *
from inserted
where ColumnX = 'MAX ID'
)
begin
-- do what you want here if ColumnX has value of 'MAX ID'
end
go
There's no way to only fire a trigger on certain DML specifications (besides insert, update, and/or delete). Your best bet is to test out the dynamic inserted table, which contains records that are inserted into YourTable. In this, you can test for inserted records that have a ColumnX value of "MAX ID".
Edit: In case you were wondering, I know you specified a for trigger in your question. A for trigger is equivalent to an after trigger in SQL Server.
You need to be aware that triggers run once for a batch, not once per row. As such, you may be running in a circumstance in which some of the rows match your criteria, and others do not.
As such, you'd do best to write your trigger logic to select the matching rows from inserted. If there were no matching rows, the rest of your logic will be working with an empty set, but that's no real problem - SQL Server is plenty fast enough at doing nothing, when required.
E.g. if you're inserting these rows into an audit table, something like:
create trigger MacId
on T
for insert
as
insert into Audit(Col1,Col2,Col3)
select i.Col1,i.Col2,'inserted'
from inserted i
where i.Col4 = 'MAC ID'