Trigger error, the error from if condition - sql-server-2005

In my application, data should be entered using a Web interface. If I enter the same section id, then error message should be displayed.
I have a meeting table, there is no value in the table.
this is my trigger
Alter trigger fourone
On MEETING
INSTEAD OF Insert
As
IF(EXISTS(
SELECT
NULL
FROM
MEETING
WHERE EXISTS
(
SELECT
NULL
FROM
inserted
WHERE
inserted.SECTION_ID=MEETING.SECTION_ID
)
)
)
BEGIN
raiserror('ERRORRRRRRRR',15,1);
END
There is no error in the trigger.
However, if I enter any value, then it's always displayed error message.
Can you guys give me answer?
thank you

Maybe you shouldn't use a trigger for a job that can be handled by a UNIQUE constraint. Define such a constraint, then, after an insert attempt, catch the exception of violating the unique constraint and notify the user accordingly.

It should not be instead of, but after insert trigger. Instead of tells sql server that you are going to insert data yourself.
Your condition is also too complex:
IF EXISTS(SELECT NULL
FROM meetings inner join inserted
on inserted.SECTION_ID=MEETING.SECTION_ID
and inserted.id <> meeting.id
)
EDIT: correction. At the time trigger gets invoked you row is already inserted. You need to test for existance of section_id excluding rows in inserted. See revised code and replace ID with primary key of meeting table. You should add rollback after raiserror otherwise new rows will remain in meetings.

Related

SQL Server trigger thinks there's a duplicate in the table when there isn't

I'm a new SQL developer. After recommendations I have altered my trigger (for this task I need to use a trigger so can't avoid it), but I have re-altered my trigger. I want it to prevent a duplication in the Rentals table of the BikeID foreign key contained within it.
This is my code at the moment:
CREATE TRIGGER BikeNotAvailable
ON dbo.SA_Rental
AFTER INSERT
AS
IF EXISTS (SELECT *
FROM SA_Rental
INNER JOIN inserted i ON i.BikeID = dbo.SA_Rental.BikeID)
BEGIN
ROLLBACK
RAISERROR ('This bike is already being hired', 16, 1);
END
go
But when I enter the BikeID in the Rentals table, even though the BikeID is not present inside a row yet, it still raises the error - why? (I have also tested this on an empty table and it still raises the error)
Just some context on my data, the BikeID is a primary key from the 'Bike' table that is shared as a foreign key to the Rentals table, not sure if this has anything to do with the error.
Can someone please help me fix this trigger so it works.
Thanks.
Well, as it's an AFTER trigger, the trigger is run after the new record is added to the table (at least visible for your trigger).
Supposing that your table has an automatically generated ID column, you should exclude the inserted row from your check like this:
CREATE TRIGGER BikeNotAvailable ON dbo.SA_Rental
AFTER INSERT
AS
if exists ( select * from SA_Rental
inner join inserted i on i.BikeID=dbo.SA_Rental.BikeID
where SA_Rental.RentalID <> i.RentalID)
begin
rollback
RAISERROR ('This bike is already being hired', 16, 1);
end
go
A far simpler way to achieve what you are after is to create a unique index:
CREATE UNIQUE INDEX BikeRented ON SA_Rental (BikeID);
This, of course, assumes that you delete the row from your table when the bike is no longer rented (as this is the implied logic in your post). If this is not the case, then we need more detail; what specifies on your table that the rental has completed?
If we assume you have a return date, and the return date is NULL when the bike is yet to be returned, then you would use a filtered index like so:
CREATE UNIQUE INDEX BikeRented ON SA_Rental (BikeID)
WHERE ReturnedDate IS NULL;

How do you update a datetime field in a table every time another field in the same table gets updated?

I have a table called YearTable with three columns (Year, Status, and LastUpdatedTime). Every time someone adds/updates a value into the year or status column LastUpdatedTime needs to be updated. I wrote a trigger for this, but now every time I try to add a new record I get an error message:
ErrorSource: .NetSqlClient Data Provider.
Error Message: Cannot insert the value NULL into Column 'Year', table 'Budget.YearTable'; column does not allow nulls. Insert fails.
This is the trigger:
CREATE TRIGGER UpdateTrigger
ON YearTable
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
insert into tblaudit(LastUpdatedTime)
values(GETDATE())
END
GO
You stated:
I wrote a trigger for this, but now every time I try to add a new record I get an error message:
ErrorSource: .NetSqlClient Data Provider. Error Message: Cannot insert the value NULL into Column 'Year', table 'Budget.YearTable'; column does not allow nulls. Insert fails.
From this, does this mean your updates and deletes are working? If that is the case, then it sounds like just like the error message states. When you're doing an insert into the table, you aren't supplying a value for the year column on the YearTable.
Have you tried disabling the trigger and seeing if the behavior exists when doing the same operations?
After further consideration of your question, I'm now assuming you're meaning that when a row in YearTable is updated, that that same row in YearTable has its LastUpdated column updated. Though now I'm not really sure where your tblAudit is coming from. Or why you would have the trigger created for deletes when there would be no row to update at that point.
I'm going to assume that your key on the table is year - if you don't currently have a key, you probably need one.
To handle the LastUpdated for inserts/updates you could use the following in your trigger (assuming year is your key):
UPDATE YearTable
SET LastUpdated = GetDate()
FROM inserted
where YearTable.Year = inserted.year

DB2 locking when no record yet exists

I have a table, something like:
create table state {foo int not null, bar int not null, baz varchar(32)};
create unique index on state(foo,bar);
I'd like to lock for a unique record in this table. However, if there's no existing record I'd like to prevent anyone else from inserting a record, but without inserting myself.
I'd use "FOR UPDATE WITH RS USE AND KEEP EXCLUSIVE LOCKS" but that only seems to work if the record exists.
A) You can let DB2 create every ID number. Let's say you have defined your Customer table
CREATE TABLE Customers
( CustomerID Int NOT NULL
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY
, Name Varchar(50)
, Billing_Type Char(1)
, Balance Dec(9,2) NOT NULL DEFAULT
);
Insert rows without specifying the CustomerID, since DB2 will always produce the value for you.
INSERT INTO Customers
(Name, Billing_Type)
VALUES
(:cname, :billtype);
If you need to know what the last value assigned in your session was, you can then use the IDENTITY_VAL_LOCAL() function.
B) In my environment, I generally specify GENERATED BY DEFAULT. This is in part due to the nature of our principle programming language, ILE RPG-IV, where developers have traditionally to allowed the compiler to use the entire record definition. This leads me to I can tell everyone to use a sequence to generate ID values for a given table or set of tables.
You can grant select to only you, but if there are others with secadm or other privileges, they could insert.
You can do something with a trigger, something like check the current session, and if the user is your user, then it inserts the row.
if (SESSION_USER <> 'Alex) then
rollback -- or generate an exception
end if;
It seems that you also want to keep just one row, then, you can control that also in a trigger:
select count(0) into value from state
if (value > 1) then
rollback -- or generate an exception
end if;

Delete and Insert or Select and Update

We have a status table. When the status changes we currently delete the old record and insert a new.
We are wondering if it would be faster to do a select to check if it exists followed by an insert or update.
Although similar to the following question, it is not the same, since we are changing individual records and the other question was doing a total table refresh.
DELETE, INSERT vs UPDATE || INSERT
Since you're talking SQL Server 2008, have you considered MERGE? It's a single statement that allows you to do an update or insert:
create table T1 (
ID int not null,
Val1 varchar(10) not null
)
go
insert into T1 (ID,Val1)
select 1,'abc'
go
merge into T1
using (select 1 as ID,'def' as Val1) upd on T1.ID = upd.ID --<-- These identify the row you want to update/insert and the new value you want to set. They could be #parameters
when matched then update set Val1 = upd.Val1
when not matched then insert (ID,Val1) values (upd.ID,upd.Val1);
What about INSERT ... ON DUPLICATE KEY? First doing a select to check if a record exists and checking in your program the result of that creates a race condition. That might not be important in your case if there is only a single instance of the program however.
INSERT INTO users (username, email) VALUES ('Jo', 'jo#email.com')
ON DUPLICATE KEY UPDATE email = 'jo#email.com'
You can use ##ROWCOUNT and perform UPDATE. If it was 0 rows affected - then perform INSERT after, nothing otherwise.
Your suggestion would mean always two instructions for each status change. The usual way is to do an UPDATE and then check if the operation changed any rows (Most databases have a variable like ROWCOUNT which should be greater than 0 if something changed). If it didn't, do an INSERT.
Search for UPSERT for find patterns for your specific DBMS
Personally, I think the UPDATE method is the best. Instead of doing a SELECT first to check if a record already exists, you can first attempt an UPDATE but if no rows are affected (using ##ROWCOUNT) you can do an INSERT.
The reason for this is that sooner or later you might want to track status changes, and the best way to do this would be to keep an audit trail of all changes using a trigger on the status table.

sql server 2008 multiple inserts over 2 tables

I got the following trigger on my sql server 2008 database
CREATE TRIGGER tr_check_stoelen
ON Passenger
AFTER INSERT, UPDATE
AS
BEGIN
IF EXISTS(
SELECT 1
FROM Passenger p
INNER JOIN Inserted i on i.flight= p.flight
WHERE p.flight= i.flightAND p.seat= i.seat
)
BEGIN
RAISERROR('Seat taken!',16,1)
ROLLBACK TRAN
END
END
The trigger is throwing errors when i try to run the query below. This query i supposed to insert two different passengers in a database on two different flights. I'm sure both seats aren't taken, but i can't figure out why the trigger is giving me the error. Does it have to do something with correlation?
INSERT INTO passagier VALUES
(13392,5315,3,'Janssen Z','2A','October 30, 2006 10:43','M'),
(13333,5316,2,'Janssen Q','2A','October 30, 2006 11:51','V')
UPDATE:
The table looks as below
CREATE TABLE Passagier
(
passengernumber int NOT NULL CONSTRAINT PK_passagier PRIMARY KEY(passagiernummer),
flight int NOT NULL CONSTRAINT FK_passagier_vlucht REFERENCES vlucht(vluchtnummer)
ON UPDATE NO ACTION ON DELETE NO ACTION,
desk int NULL CONSTRAINT FK_passagier_balie REFERENCES balie(balienummer)
ON UPDATE NO ACTION ON DELETE NO ACTION,
name varchar(255) NOT NULL,
seat char(3) NULL,
checkInTime datetime NULL,
gender char(1) NULL
)
There are a few problems with this subquery:
SELECT 1
FROM Passenger p
INNER JOIN Inserted i on i.flight= p.flight
WHERE p.flight= i.flight AND p.seat= i.seat
First of all, the WHERE p.flight = i.flight is quite unnecessary, as it's already part of your join.
Second, the p.seat = i.seat should also be part of the JOIN.
Third, this trigger runs after the rows have been inserted, so this will always match, and your trigger will therefore always raise an error and roll back.
You can fix the trigger, but a much better method would be to not use a trigger at all. If I understand what you're trying to do correctly, all you need is a UNIQUE constraint on flight, seat:
ALTER TABLE passgier
ADD CONSTRAINT IX_passagier_flightseat
UNIQUE (flight, seat)
If you run your trigger after inserting a record, and then look for a record with the values you just inserted, you will always find it. You might try an INSTEAD OF trigger so you can check for an existing records before actually doing the insert.
It might be throwing the error by finding itself in the table (circular reference back to itself). You might want to add an additional filter to the where clause like " AND Passenger.ID <> inserted.ID "