i made an stored proc
ALTER proc [dbo].[MakeOrder]
#barcode varchar(50),
#packs int ,
#units int,
#Eid int
as
begin
insert into Orders (Barcode,Price,PacksQty,UnitQty)
values (#barcode,dbo.GetOrderPackPrice(#packs,#barcode)+dbo.GetOrderUniPrice(#units,#barcode),#packs,#units)
insert into OrderDetails(Eid,Date)
values (#Eid,GETDATE())
update Product
set Stock = Stock-#packs , UnitsStock = UnitsStock-#units where BarCode=#barcode
end
and i want to make after update trigger on product table to check the value of UnitsStock Column After Update If it 0 do something else do another thing
You don't need a trigger to do this necessarily. You can simply select the value of this column out again:
DECLARE #currentUnits int
SELECT #currentUnits = UnitsStock FROM Product WHERE BarCode = #barcode
and then build in some conditional logic:
IF #currentUnits <= 0
BEGIN
-- Do something
END
ELSE
BEGIN
-- Do something else
END
Since you're not checking whether the number of units being ordered is less than the current UnitsStock, you're better off with a check for <= 0, or maybe even a separate check for < 0 to handle this differently still.
This code should go in your stored procedure, after the UPDATE statement.
Related
I have a MySQL database in which I have the following rows (by exemple) created by default (id, task and case may be different but the current value is always 1)
....idtaskcaseuser............datecurrent
238......31001.....0..............null..........1
239......41001.....0..............null..........1
I have to randomly create rows like this with insert statement (new rows). As you can see a date is filled and de current equal 0
....idtaskcaseuser............datecurrent
240......51001.....12015.04.03..........0
241......21002.....12015.04.03..........0
When I come across one of the lines created by default I want to use an update instead of an insert statement.
So I created the following procedure in MySQL
DELIMITER //
DROP PROCEDURE IF EXISTS FillProgress//
CREATE PROCEDURE FillProgress ( get_case INT(10),get_task INT(10), get_user INT(10) )
BEGIN
DECLARE test tinyint(1);
SET test = (SELECT COUNT(*) FROM progress WHERE case_id = get_case AND task_id = get_task);
IF test = 1 THEN
UPDATE progress SET current = 0, date = NOW(), user_id = get_user WHERE task_id = get_id AND case_id = get_case;
ELSE
INSERT INTO progress(task_id,case_id,user_id,date,current) VALUES (get_task,get_case,get_user,NOW(),0);
END IF;
END; //
DELIMITER ;
I use count to see if a already have a row with the same case and task. If it's true (test=1) I use UPDATE, otherwise and use INSERT.
If I test with the following row already wrote in the database
....idtaskcaseuserdatecurrent
241......41001.....0..null..........1
I use CALL FillProgress(1001,4,1);
The row is not updated, but I do not have any error message.
11:38:02 CALL FillProgress(1001,4,1) 0 row(s) affected 0.000 sec
And if I manually use my update query
UPDATE progress SET current = 0, date = NOW(), user_id = 1 WHERE task_id = 4 AND case_id = 1001;
It works like a charm.
The insert query also works fine.
The UPDATE query within the procedure has a "WHERE task_id = get_id" clause, however I don't see get_id being defined in the procedure; there is a "get_task" parameter for the stored procedure, though.
I did a trigger in mysql to shoot alerts always an input value was less than the set value. But now I need it is done in SQL SERVER.
I would be grateful if someone could help me transform mysql trigger to a SQL Server trigger.
Thanks to all at once.
My trigger is:
DELIMITER $$
create TRIGGER alert
AFTER INSERT ON records
FOR EACH ROW
begin
Set #comp=0;
Set #tempmax=0;
Set #tempmin=0;
select lim_inf_temp into #tempmin from sensores where idSensor=NEW.idSensor;
Set #maxidAlarme=0;
if (CAST(NEW.Temperatura AS UNSIGNED)<#tempmin) then
SELECT MAX(idAlarme) into #maxidAlarme FROM alarmes;
SET #maxidAlarme=#maxidAlarme+1;
INSERT INTO alarmes(idAlarme,descricao_alarme, idRegisto) VALUES (#maxidAlarme,"inserted below the normal temperature",New.idRegisto);
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme) VALUES (NEW.idSensor,#maxidAlarme,NOW());
set #comp=+1;
end if;
set #id_sensores_em_alerta=1;
SELECT MAX(id_sensores_em_alerta) into #id_sensores_em_alerta FROM sensores_em_alerta;
INSERT INTO sensores_em_alerta(id_sensores_em_alerta, idSensor, idAlarme, data_registo, numerosensoresdisparados) VALUES (id_sensores_em_alerta,NEW.idSensor, #maxidAlarme, NOW(), #comp);
end $$;
DELIMITER ;
I've tried to make the trigger in SQL Server, but as the script is different and I'm getting many difficulties to do the right way.
My attempt that was not going at all well:
CREATE TRIGGER Alert ON registos AFTER INSERT AS
BEGIN
DECLARE #comp decimal= 0
DECLARE #tempmax decimal= 0
DECLARE #tempmin decimal= 0
DECLARE #current_max_idAlarme int = (SELECT MAX(IdAlarme) FROM alarmes)
-- Insert into alarmes from the inserted rows if temperature less than tempmin
INSERT alarmes (IdAlarme, descricao_alarme, idRegisto)
SELECT
ROW_NUMBER() OVER (ORDER BY i.idRegisto) + #current_max_idAlarme,
'temp Error',
i.idRegisto
FROM
inserted AS i
WHERE
i.Temperatura < #tempmin
END
But dont do anything.
Dont create data on table alarmes :S
Does anyone could help me please. I would be eternally grateful.
Many Greetings and thank you all.
First of all, MSSQL doesn't have the option FOR EACH ROW, so it treats multiple inserted rows at once as a set. You will therefore have to insert the values into a table variable.
Unfortunately I do not know much MySQL actually, but I believe this is a starting point?
CREATE TRIGGER ALERT
ON records
AFTER INSERT
AS
BEGIN
DECLARE #comp INT;
DECLARE #tempmax INT;
DECLARE TABLE #tempmin (tempmin INT);
INSERT INTO #tempmin
SELECT s.lim_inf_temp FROM sensores s WHERE s.idSensor IN (inserted.idSensor);
--rest of the code
I'm going to post this code against my better judgement - redesign the tables is better than this hack.
This uses a ROW_number() to virtualise a surrogate identity key for the alarmes table. This is a 'bad plan' (tm).
Also the answer is partial - it doesn't do everything your question asked for -- I hope it gets your further along the road. Use it as a guide for how to interact with the virtual INSERTED table. Good luck
CREATE TRIGGER Alert ON records AFTER INSERT AS
BEGIN
DECLARE #comp INT = 0
DECLARE #tempmax INT = 0
DECLARE #tempmin INT = 0
-- get the max current id.
-- note that this is EXTREMELY unsafe as if two pieces of code are executing
-- at the same time then you *will* end up with key conflicts.
-- you could use SERIALIZABLE.... but better would be to redisn the schema
DECLARE #current_max_idAlarme = (SELECT MAX(IdAlarme) FROM alarmes)
-- Insert into alarmes from the inserted rows if temperature less than tempmin
INSERT alarmes (IdAlarme, descricao_alarme, idRegisto)
SELECT
ROW_NUMBER() OVER (ORDER BY i.idRegisto) + #current_max_idAlarme,
'temp Error',
i.idRegisto
FROM
inserted AS i
WHERE
i.Temperatura < #tempmin
END
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.
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
I have a stored procedure, shown below, which I created to add dollar sales to a table (WeeklySales) which currently stores only unit sales. The cursor operates on on the WeeklySales table. The pricing data is stored in the Pricing table. The Pricing table actually contains changes in prices. The effective date for a price change is stored in Pricing.effectiveDate, so I have to find the pricing which was effective for the week in which the unit was sold (which is stored in WeeklySales.weekStart).
The problem I'm having is that the first select after the IF doesn't return anything. I've confirmed that this select does return a value when I run it outside of the procedure using the values which it would be called with inside the procedure. I'm not sure what's wrong here, but I'm guessing maybe this has to do with the fact that the this select is operating on a table which is different from the cursor? Anyone know? Is there a better way to do this?
DELIMITER //
CREATE PROCEDURE `createWeeklyPricing` (IN startDate DATE, IN endDate DATE)
BEGIN
--
-- Populate the proceeds column using the Pricing table
DECLARE product VARCHAR(255);
DECLARE weekStart DATE;
DECLARE units, done INT;
DECLARE proceeds DECIMAL(6,2);
DECLARE effectiveDate DATE;
DECLARE currentRow CURSOR FOR SELECT `weekStart`, `product`, `units` FROM `WeeklySales` WHERE `weekStart` >= startDate AND `weekStart` <= endDate;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN currentRow;
SET done = 0;
WHILE done = 0 DO
FETCH currentRow INTO weekStart, product, units;
IF done = 0 THEN
SELECT MAX(`effectiveDate`) FROM `Pricing` WHERE `effectiveDate` <= weekStart AND `product` = product INTO effectiveDate;
SELECT `proceeds` FROM `Pricing` WHERE `effectiveDate` = effectiveDate AND `product` = product INTO proceeds;
UPDATE `WeeklySales` SET `proceeds` = units * proceeds WHERE `weekStart` = weekStart AND `product` = product;
END IF;
END WHILE;
CLOSE currentRow;
END//
echo (select) weekstart before the if statement...
If it returns null change the select FROM WeeklySales WHERE weekStart between startDate AND endDate
you need to use the INTO before FROM and variable needs '#' sign
change it to
SELECT MAX(`effectiveDate`) INTO #effectiveDate FROM `Pricing` WHERE `effectiveDate` <= weekStart AND `product` = product ;
hope this helps
This is because your variable name is overwriting your column name:
You have a variable named 'effectiveDate'
You have a column named 'effectiveDate'
SELECT MAX(`effectiveDate`) ...
Is MAX-ing the variable effectiveDate, not the column
Try naming the variable maxEffectiveDate
Beware that variables are case insensitive. This happened to me when i tried to select column IsBackUp into variable isBackUp (notice the i).