sql server trigger for custom PK - sql-server-2008

I want to generate PK through trigger as it is custom PK.
It is like depending on the member type field, I want to generate member id which is PK.
e.g. if new record's member type is DGIA, then member id will be DGIA1, DGIA2, DGIA3 ...and so on... if member type is DGIL, then member id will be DGIL1, DGIL2, DGIL3 ...and so on...
So, how to write trigger for the same... I have tried as following but it is working for 1st record only.
ALTER TRIGGER [dbo].[next_member_id] ON [dbo].[DAD_MEMBERSHIP] AFTER INSERT
AS
BEGIN
DECLARE #COUNT INT
SET #COUNT=0;
SELECT #COUNT=ISNULL(MAX(CAST(SUBSTRING(DAD_MEMBERSHIP.MEMBER_ID,5,15) AS INT)),0)+1 FROM DAD_MEMBERSHIP where DAD_MEMBERSHIP.MEMBER_TYPE = DAD_MEMBERSHIP.MEMBER_TYPE
update DAD_MEMBERSHIP set DAD_MEMBERSHIP.MEMBER_ID = DAD_MEMBERSHIP.MEMBER_TYPE + CONVERT(varchar,#COUNT)
from DAD_MEMBERSHIP inner join inserted on DAD_MEMBERSHIP.MEMBER_TYPE = inserted.MEMBER_TYPE
END

Triggers operate by batch of records, you cannot assign to a scalar variable and expect it to work for more than one record. You need to rethink your whole process into a set-based process.

I solved the problem using following trigger
ALTER TRIGGER [dbo].[next_member_id]
ON [dbo].[DAD_MEMBERSHIP]
AFTER INSERT
AS
BEGIN
DECLARE #COUNT INT
SET #COUNT=0;
DECLARE #STR VARCHAR(5)
SET #STR=''
select #STR=i.MEMBER_TYPE from inserted i;
SELECT #COUNT=ISNULL(MAX(CAST(SUBSTRING(DAD_MEMBERSHIP.MEMBER_ID,5,15) AS INT)),0)+1
from DAD_MEMBERSHIP where MEMBER_TYPE=#STR
update DAD_MEMBERSHIP set DAD_MEMBERSHIP.MEMBER_ID = #STR + CONVERT(varchar,#COUNT)
from DAD_MEMBERSHIP inner join inserted i on i.MEMBER_TYPE=DAD_MEMBERSHIP.MEMBER_TYPE where DAD_MEMBERSHIP.MEMBER_ID is null
END

Related

MySql trigger not works

I have 3 tables
tbl_payments(pay_id,date,amount,description,-------)
tbl_pay_trans(pay_id,trans_id)
tbl_transactions(trans_id,trans_date,trans_amount,trans_description,-----)
'tbl_transaction' has the same data from the 'tbl_payments' along with some other values. To maintain the relationship between the two tables I use 'tbl_pay_trans'. What I want to do is, when an update done on tbl_payments(amount,description) the same changes need to do in tbl_transactions(trans_amount,trans_description). I wrote a trigger to do that, but it dose not update the tbl_transaction table values as it supposed to.
My trigger is
DELIMITER $$
CREATE TRIGGER update_trans
AFTER UPDATE on tbl_payments
FOR EACH ROW
BEGIN
DECLARE new_amount VARCHAR(50);
DECLARE new_description TEXT;
DECLARE new_pay_id,new_trans_id INT;
SET new_pay_id = OLD.pay_id;
SET new_amount = OLD.amount;
SET new_description = OLD.description;
SELECT trans_id INTO new_trans_id FROM tbl_pay_trans WHERE pay_id = new_pay_id;
UPDATE tbl_transactions SET
trans_amount = new_amount,
trans_description = new_description
WHERE trans_id = new_trans_id;
END$$
DELIMITER ;
Please someone help me to figure out what I did wrong.
It's not updating because you are using OLD on the amount and description columns where you need to use NEW i.e.
SET new_amount = NEW.amount;
SET new_description = NEW.description;
OLD refers to the column value before the update occurred in tbl_payments. See the manual.

Problems with syntax on MySQL trigger in PHP My Admin

I am having problems getting this trigger to work. Here is the code:
BEGIN
DECLARE newprice double;
DECLARE id int;
DECLARE rentdate DATE;
SET id := RESERVATION.RES_ID;
SET rentdate := "SELECT RES_RENT_DATE
FROM RESERVATION
WHERE RES_ID = id";
SET newprice := (NEW.RES_RETURN_DATE - rentdate)*RESERVATION.RES_CAR_PPD;
UPDATE RESERVATION
SET RESERVATION.RES_TOTAL_PRICE = newprice WHERE
RESERVATION.RES_ID = id;
END
Basically what I want to do is just update the total price when the return date of a car is changed. The trigger should execute on update of the Return Date. When updating it gives me the error: #1109 - Unknown table 'RESERVATION' in field list . I do not know what I am doing wrong.
There are several issues:
You can't arbitrarily refer to table columns like you did in SET id := RESERVATION.RES_ID;. You can refer to columns only either in a valid SQL statement (e.g. SELECT) or through NEW/OLD.
You can't issue DML statement (in your case UPADTE) on the same table on which you defined the trigger. This mutating behavior is prohibited in MySQL.
If I understand correctly and all values you need are in the same row, all you need is to use a BEFORE trigger. See example below.
Your trigger can be boiled down to this
CREATE TRIGGER tg_bu_reservation
BEFORE UPDATE ON reservation
FOR EACH ROW
SET NEW.res_total_price = (NEW.res_return_date - NEW.res_rent_date) * NEW.res_car_ppd;
Note: since it's a one statement trigger now there is no need in BEGIN...END block and changing a DELIMITER.
Here is SQLFiddle demo

sql server UPDATE TRIGGER doesn't fire

i have a trigger like below, the logic is to change FID status after fidRule status changed.
in my app, i update 1 row in each statement,
but i found sometimes(very rare) the trigger not firing.
ALTER TRIGGER [dbo].[triggerSetFIDStatus]
ON [dbo].[FIDRules]
AFTER UPDATE
AS
BEGIN
set nocount on
DECLARE #ruleStatus INT
DECLARE #newRuleStatus INT
DECLARE #FIDAlertStatus INT
DECLARE #FIDId INT
DECLARE #isFIDEnabled int
DECLARE #ruleId INT
SELECT #ruleStatus = deleted.alertStatus,
#FIDId = deleted.FIDID,
#ruleId = deleted.id
from
deleted
SELECT #newRuleStatus = inserted.alertStatus
from
inserted
SELECT #FIDAlertStatus = alertStatus,
#isFIDEnabled= isEnabled
FROM FID
WHERE id = #FIDId
IF #FIDAlertStatus <> #newRuleStatus
BEGIN
-- change FID-status by FIDRule-status
UPDATE [dbo].[FID] SET alertStatus=#newRuleStatus WHERE id=#FIDId
END
IF #newRuleStatus >= 0 AND #newRuleStatus <> #ruleStatus
UPDATE [dbo].[FIDRules] SET isAlertStatChanged=1, AlertStatChangeTime = SYSUTCDATETIME() WHERE id=#ruleId
END
The trigger will not be fired if the UPDATE statement fails or another triggers fails to execute before this trigger is fired.
One comment about your trigger itself:
You are expecting one records from DELETED which is not always correct.
Please make your trigger robust enough in case DELETED contains multiple records
-- What if deleted contains multiple records?
SELECT #ruleStatus = deleted.alertStatus,
#FIDId = deleted.FIDID,
#ruleId = deleted.id
FROM
deleted
You can either use SELECT TOP(1) or make sure your trigger is able to handle multiple records from the DELETED list.

Update Trigger : Supertype/subtypes tables

I need some help about triggers. I’m currently developing a platform and a database in order to manage exams at my university. Here is my problem:
I have 1 supertype table, which contains all the persons registered on the platform. I have to be able to make the distinction for each person between the functions “Candidate” and “Examiner”. So I have my 2 subtype tables, one for all the candidates and one for all the examiners. To achieve that, I’m using insert triggers.
In addition, a person can be both Candidate and Examiner, but not at the same time. So after updating the supertype table, I also need a trigger to be able to delete a specific row from one of the two-subtype table and insert the user information on the other.
Here is a simplified design of these 3 tables:
My INSERT trigger :
ALTER TRIGGER [dbo].[role_insert]
ON [dbo].[alemp_persons]
FOR INSERT
AS
DECLARE #random_number int
SELECT #random_number = CAST(CAST(rand() as binary(2)) as int)
BEGIN
INSERT INTO dbo.alemp_candidates
(
id_person, random_number
)
SELECT id_person, # random_number
FROM INSERTED
WHERE function='Candidate'
INSERT INTO dbo.alemp_examiners
(
id_person
)
SELECT id_person
FROM INSERTED
Where function='Examiner'
END
GO
My UPDATE trigger :
ALTER TRIGGER [dbo].[role_update] ON [dbo].[alemp_persons]
AFTER UPDATE
AS
DECLARE #id_person int
DECLARE #newFunction int SELECT #newFunction=function FROM inserted
DECLARE #random_number int SELECT # random_number = CAST(CAST(rand() as binary(2)) as int)
IF #newFunction = 'Candidate'
BEGIN
DELETE
FROM dbo.alemp_examiners
WHERE id_person=#id_person
END
BEGIN
SET IDENTITY_INSERT dbo.alemp_candidates ON;
INSERT INTO dbo.alemp_candidates
(
id_person, random_number
)
SELECT #id_person, random_number
SET IDENTITY_INSERT dbo.alemp_candidates OFF;
END
IF #newFunction = 'Examiner'
BEGIN
DELETE
FROM dbo.alemp_candidates
WHERE id_person=#id_person
END
BEGIN
SET IDENTITY_INSERT dbo.alemp_examiners ON;
INSERT INTO dbo.alemp_examiners
(
id_person
)
SELECT #id_person
SET IDENTITY_INSERT dbo.alemp_examiners Off;
END
GO
As I said above, my INSERT trigger works as I want. However when I want to update the function of one person, I got an error :
Explicit value must be specified for identity column either when IDENTITY_INSERT is set
to ON or when a replication user is inserting into a NOT FOR REPLICATION identity column.
Some simple notes:
1) You should follow Mitch Wheat's advice and rewrite these triggers because inserted and deleted tables could have more than one row. For example, your trigger will have a bad behavior when is executed the next statement UPDATE [dbo].[alemp_persons] SET function = CASE WHEN id_person = 1 THEN 'Candidate' ELSE 'Examiner' END WHERE id_person IN (1,2) if the first person's function is 'Examiner' and the second person's function is 'Candidate'.
2) [dbo].[alemp_persons].function's data type should be [tiny]int or char(1) and not varchar(something greater than 1) (Where function='Examiner').
3) [dbo].[alemp_persons].function column should disallow Nulls.
4) [dbo].[alemp_persons].function column should has a CHECK constraint:
ALTER TABLE [dbo].[alemp_persons]
ADD CONSTRAINT CK_alemp_persons_function_Verify CHECK ( function IN ('Candidate', 'Examiner') );
5) It would be nice to add
a function column to [dbo].[alemp_candidates] and [dbo].[alemp_examiners] tables,
two check constraints on [dbo].[alemp_candidates] (function = 'Candidate') and [dbo].[alemp_examiners] (function = 'Examiner'),
an UNIQUE index on [dbo].[alemp_persons](id_person, function),
two FKs between [dbo].[alemp_candidates/examiners](id_person, function) and [dbo].[alemp_persons](id_person, function).
This way, you can be sure that [dbo].[alemp_candidates] table has only candidates and [dbo].[alemp_examiners] has only examiners and every person can be only candidate or examiner at one time.
6) You should disallow IDENTITY property for id_person columns in [dbo].[alemp_candidates] and [dbo].[alemp_examiners] table (SET IDENTITY_INSERT dbo.alemp_candidates ...).
8) And this statement IF #newFunction = 'Candidate' should raise an error because #newFunction data type is 'INT'.
9) And the AFTER UPDATE trigger on [dbo].[alemp_persons] table will move data between candidates and examiners tables (not tested):
ALTER TRIGGER [dbo].[role_update]
ON [dbo].[alemp_persons]
FOR UPDATE
AS
BEGIN
DECLARE #selected_rows TABLE (
id_person INT PRIMARY KEY, -- or BIGINT, look at alemp_person.id_person data type
new_function VARCHAR(50) NOT NULL -- look at alemp_person.function column data type
);
INSERT #selected_rows (id_person, new_function)
SELECT new.id_person, new.function
FROM inserted as new INNER JOIN deleted as old ON new.id_person = old.id_person
WHERE new.function <> old.function;
MERGER dbo.alemp_candidates AS dest
USING #selected_rows AS src ON dest.id_person = src.id_person
WHEN MATCHED THEN
DELETE
WHEN NOT MATCHED BY TARGET AND src.new_function = 'Candidate' THEN
INSERT (id_person, random_number)
VALUES (src.id_person, CONVERT(BINARY(2), CHECKSUM(NEWID()));
MERGER dbo.alemp_examiners AS dest
USING #selected_rows AS src ON dest.id_person = src.id_person
WHEN MATCHED THEN
DELETE
WHEN NOT MATCHED BY TARGET AND src.new_function = 'Examiner' THEN
INSERT (id_person)
VALUES (src.id_person);
END

Is it possible to use the Sql MERGE syntax to UPDATE / INSERT data from another variable TABLE?

I wish to Insert or Update a row in a table - so I wish to try and use the MERGE syntax. My problem is that my data (to insert/update) exists in a variable table. I'm not sure how to write the correct syntax for the insert/update part.
Here's my pseduo code :-
-- Here's the Variable Table ... and not it has not PK.
DECLARE #PersonId INTEGER
DECLARE #variableTable TABLE (
#SomeScore DECIMAL(10,7),
#SomeAverage DECIMAL(10,7),
#SomeCount INTEGER)
-- Insert or Update
MERGE INTO SomeTable
WHERE PersonId = #PersonId
WHEN MATCHED THEN
UPDATE
SET PersonScore = ??????????
PersonAverage = ???????
PersonCount = ????????
WHEN NOT MATCHED THEN
INSERT(PersonId, PersonScore, PersonAverage, PersonCount)
VALUES(#PersonId, ????, ?????, ????)
.. and I'm not sure how I make sure the UPDATE correctly only updates 1 row (ie... does that need a WHERE clause?)
Finally, I based my this post on this SO question.
Yes it's possible. Your syntax was off though. The below seems to work. I have kept #PersonId as a separate scalar variable outside the table variable as that's how you have it in your question. And I have assumed that the Primary Key of SomeTable is PersonId
DECLARE #PersonId INT
DECLARE #variableTable TABLE (
SomeScore DECIMAL(10,7),
SomeAverage DECIMAL(10,7),
SomeCount INTEGER
)
-- Insert or Update
MERGE SomeTable AS T
USING #variableTable AS S
ON (T.PersonId = #PersonId)
WHEN MATCHED THEN
UPDATE
SET T.PersonScore = SomeScore,
T.PersonAverage = SomeAverage,
T.PersonCount = SomeCount
WHEN NOT MATCHED BY TARGET THEN
INSERT(PersonId, PersonScore, PersonAverage, PersonCount)
VALUES(#PersonId, SomeScore, SomeAverage, SomeCount);