converting a mySQL Trigger, to TSQL - mysql

Looking for help converting this mySQL Trigger, to TSQL.
CREATE TRIGGER IF not exists TF_WATCHLIST_PERSISTENCE_ADD_POSITION
AFTER INSERT ON TF_WATCHLIST_PERSISTENCE
FOR EACH ROW
WHEN NEW.WATCHLIST_POSITION IS NULL
BEGIN
UPDATE TF_WATCHLIST_PERSISTENCE SET
WATCHLIST_POSITION = (SELECT COUNT(*) - 1 FROM TF_WATCHLIST_PERSISTENCE WHERE WATCHLIST_USER = NEW.WATCHLIST_USER)
WHERE rowid = NEW.rowid;
END;

Thanks for all your help
I ended up with this.
CREATE TRIGGER TF_WATCHLIST_PERSISTENCE_ADD_POSITION
ON TF_WATCHLIST_PERSISTENCE
AFTER INSERT, UPDATE
AS
DECLARE #MyCursor CURSOR;
DECLARE #MyField_USER varchar(250);
DECLARE #MyField_ID varchar(250);
DECLARE #MyField_NewPos int
BEGIN
SET #MyCursor = CURSOR FOR
SELECT WATCHLIST_USER
, WATCHLIST_ID
FROM inserted
WHERE inserted.WATCHLIST_POSITION is null
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #MyField_USER, #MyField_ID
WHILE ##FETCH_STATUS = 0
BEGIN
set #MyField_NewPos = (SELECT MAX(WATCHLIST_POSITION) + 1 FROM TF_WATCHLIST_PERSISTENCE WHERE WATCHLIST_USER = #MyField_USER)
print #MyField_NewPos
update TF_WATCHLIST_PERSISTENCE
SET WATCHLIST_POSITION = ISNULL(#MyField_NewPos,0)
WHERE WATCHLIST_USER = #MyField_USER
AND WATCHLIST_ID = #MyField_ID
AND WATCHLIST_POSITION IS NULL
Print #MyField_USER
Print #MyField_ID
FETCH NEXT FROM #MyCursor
INTO #MyField_USER, #MyField_ID
END;
END;
CLOSE #MyCursor

Try this:
CREATE TRIGGER TF_WATCHLIST_PERSISTENCE_ADD_POSITION ON TF_WATCHLIST_PERSISTENCE AFTER INSERT
AS
BEGIN
WITH DataSource AS
(
SELECT DS.WATCHLIST_USER
,COUNT(*) - 1 AS WATCHLIST_POSITION
FROM TF_WATCHLIST_PERSISTENCE DS
INNER JOIN inserted I
ON DS.WATCHLIST_USER = I.WATCHLIST_USER
WHERE inserted.WATCHLIST_POSITION is null
GROUP BY DS.WATCHLIST_USER
)
UPDATE TF_WATCHLIST_PERSISTENCE
SET WATCHLIST_POSITION = DS.[WATCHLIST_POSITION]
FROM TF_WATCHLIST_PERSISTENCE DS
INNER JOIN DataSource I
ON DS.WATCHLIST_USER = I.WATCHLIST_USER;
END

I suspect you are looking for a ranking function, or even a simple COUNT(*) per user? MySQL is rather poor in analytic, ranking or windowing functions so tricks like quirky updates or triggers are used to emulate them.
In SQL Server, you could return the number of records that match a single user in each row with COUNT() applied over the records that match a single user :
SELECT *, COUNT(*) OVER (PARTITION BY WATCHLIST_USER)
FROM TF_WATCHLIST_PERSISTENCE
No need for a trigger. You can use any aggregate with an OVER() clause.
If you want the rank according to some order, you can use one of the ranking functions like ROW_NUMBER() or `RANK(). If you want to calculate a row position per user based, eg on creation date you could write :
SELECT *, ROW_NUMBER(*) OVER (PARTITION BY WATCHLIST_USER ORDER BY CreationDate)
FROM TF_WATCHLIST_PERSISTENCE
If you have an incrementing ID you could use it to generate a row position per user
SELECT *, ROW_NUMBER(*) OVER (PARTITION BY WATCHLIST_USER ORDER BY ID)
FROM TF_WATCHLIST_PERSISTENCE
Most of the time, you don't need to store the row position. It's simple enough to add a ranking function to a query.
If you do need to store such a row position in a table, you could use a simple multi-row trigger
CREATE TRIGGER TF_WATCHLIST_PERSISTENCE_ADD_POSITION
ON TF_WATCHLIST_PERSISTENCE
AFTER INSERT, UPDATE
AS
update TF_WATCHLIST_PERSISTENCE
set WATCHLIST_POSITION =ROW_NUMBER() OVER (PARTITION BY WATCHLIST_USER ORDER BY ID)
FROM inserted
INNER JOIN TF_WATCHLIST_PERSISTENCE on inserted.ID=TF_WATCHLIST_PERSISTENCE.ID
Or
update TF_WATCHLIST_PERSISTENCE
set WATCHLIST_POSITION =ROW_NUMBER() OVER (PARTITION BY WATCHLIST_USER ORDER BY ID)
FROM inserted
INNER JOIN TF_WATCHLIST_PERSISTENCE
ON inserted.WATCHLIST_USER =TF_WATCHLIST_PERSISTENCE.WATCHLIST_USER
If you want to insert new entries for an existing user and recalculate all positions

Related

IN clause not working in WHERE condition in MYSQL Trigger

I am creating a trigger that have a MYSQL query having IN clause look like below.
drop trigger onPublish;
delimiter $$
create trigger onPublish AFTER insert on publish_drawing_details
for each row
begin
Declare userIds VARCHAR(255);
set userIds = (select GROUP_CONCAT(refUser) from manpower where refProject=new.refProjectId and refRoleType in (select role from hr_user));
insert into notification_container(loginUserId,mailSubject,projectId,userIds,attachmentIds,ccMails,mailText,metaNotificationEventId)
values (new.submittedBy,new.mailSubject,new.refProjectId,userIds,new.attachmentIds,new.ccEmails,new.mailText,1);
end $$
It works fine if I write this like set userIds = (select GROUP_CONCAT(refUser) from manpower where refProject=new.refProjectId and refRoleType in (1,2,3,4,5));
I try it like set userIds = (select GROUP_CONCAT(refUser) from manpower where refProject=new.refProjectId and refRoleType in (select GROUP_CONCAT(role) from hr_user));
but don't work at all.
You don't need GROUP_CONCAT in inner query, try the following:
SET userIds = (
SELECT GROUP_CONCAT(refUser)
FROM manpower
WHERE refProject=new.refProjectId
AND refRoleType IN (
SELECT role
FROM hr_user
)
);

Summing the values from the 2nd table based on ID of the 1st table and inserting values in first table

How to in first table where it says UkupnaCena insert sum value of column Cena where RacunID in first table is equal to RacunID in other table. For example if RacunID is equal to 1 in first table, I want its UkupnaCena to be equal to sum of all values in column Cena where RacunID is 1.
Tables:
My procedure so far:
Create procedure sp_RacunUpdate(
#pRacunID int,
#pStatusRacuna nvarchar(50),
#pDatum nvarchar(20),
#pOpis nvarchar(200),
#pMesto nvarchar(50),
#pKupacID int
)
as begin
Declare #pUkupnaCena decimal(20,2)
select #pUkupnaCena=sum(Cena) from Stavka
inner join Racun
on Racun.RacunID=Stavka.RacunID
Where Racun.RacunID=Stavka.RacunID
group by Stavka.RacunID
begin transaction
UPDATE Racun
SET StatusRacuna=#pStatusRacuna, Datum=#pDatum, Opis=#pOpis,Mesto=#pMesto,UkupnaCena=#pUkupnaCena,KupacID=#pKupacID
WHERE RacunID=#pRacunID
IF ##ERROR <> 0
BEGIN
ROLLBACK
END
ELSE
BEGIN
COMMIT
END
END
GO
You can modify the update query to something like this
UPDATE Racun from Racun
SET UkupnaCena=(select sum(Cena) from Stavka s where s.RacunID= Racun.RacunID), Datum=#pDatum, Opis=#pOpis,Mesto=#pMesto,KupacID=#pKupacID
WHERE RacunID=#pRacunID
I believe you want a correlated subquery. In MySQL, this would look like:
UPDATE Racun r
SET StatusRacuna = #pStatusRacuna,
Datum = #pDatum,
Opis = #pOpis,
Mesto = #pMesto,
KupacID = #pKupacID,
UkupnaCena = (SELECT SUM(s.Cena) FROM Stavka s WHERE s.RacunID = r.RacunId)
WHERE RacunID = #pRacunID;
However, your code does not look like MySQL; it looks more like SQL Server. In either database, you can do:
UPDATE Racun
SET StatusRacuna = #pStatusRacuna,
Datum = #pDatum,
Opis = #pOpis,
Mesto = #pMesto,
KupacID = #pKupacID,
UkupnaCena = (SELECT SUM(s.Cena) FROM Stavka s WHERE s.RacunID = Racun.RacunId)
WHERE RacunID = #pRacunID;
The only difference here is removing the table alias in the outer query.

MySQL - Update Column Value with Function and Trigger Before Insert

i'm trying to update 2 column with trigger before insert, but i have unexpected result. i insert some data and the 2 last column will automatically inserted with values, here my first attempt
see? the last 2 column is null even i set some trigger and function to fill that columns automatically. Here my second attempt WITH EXACTLY SAME DATA
the last 2 column is filled with data, but i don't understand why the first attempt is fail?
here my trigger i use in the column total_harga
CREATE TRIGGER `set_total_harga` BEFORE INSERT ON `tbl_transaksi_detail`
FOR EACH ROW BEGIN
set NEW.total_harga = hitungTotalHargaPerItem(NEW.qty, NEW.harga_satuan);
END
trigger for column harga_satuan
CREATE TRIGGER `set_harga_satuan` BEFORE INSERT ON `tbl_transaksi_detail`
FOR EACH ROW BEGIN
set NEW.harga_satuan = set_Harga_Unit(NEW.unit, NEW.id_barang, NEW.no_transaksi);
END
function set_Harga_Unit
BEGIN
DECLARE
q,
id_toko INT;
SET
id_toko =(
SELECT DISTINCT
`tbl_transaksi`.`id_toko`
FROM
`tbl_transaksi`,
`tbl_transaksi_detail`
WHERE
`tbl_transaksi`.`no_transaksi` = no_trans
); IF unit = "PCS" THEN
SET
q =(
SELECT
`tbl_harga_jual`.`harga_pcs`
FROM
`tbl_harga_jual`
WHERE
`tbl_harga_jual`.`id_barang` = id_brg AND `tbl_harga_jual`.`id_toko` = id_toko
); RETURN q; ELSEIF unit = "PAK" THEN
SET
q =(
SELECT
`tbl_harga_jual`.`harga_pak`
FROM
`tbl_harga_jual`
WHERE
`tbl_harga_jual`.`id_barang` = id_brg AND `tbl_harga_jual`.`id_toko` = id_toko
); RETURN q; ELSEIF unit = "KARTON" THEN
SET
q =(
SELECT
`tbl_harga_jual`.`harga_karton`
FROM
`tbl_harga_jual`
WHERE
`tbl_harga_jual`.`id_barang` = id_brg AND `tbl_harga_jual`.`id_toko` = id_toko
); RETURN q;
END IF; RETURN q;
END
function hitungTotalHargaPerItem
BEGIN
DECLARE hasil int;
set hasil = qty * harga_satuan;
RETURN hasil;
END
The root cause serms to be the select that sets id_toko variable's value:
SET
id_toko =(
SELECT DISTINCT
`tbl_transaksi`.`id_toko`
FROM
`tbl_transaksi`,
`tbl_transaksi_detail`
WHERE
`tbl_transaksi`.`no_transaksi` = no_trans
);
In the select you inner join tbl_transaksi_detail (the table with the trigger in question) on another table. However, in the 1st case tbl_transaksi_detail is still empty (the trigger is before insert), therefore id_toko variable is set to null.
This will result q being null, which in turn results in the entire calculation set to null.
In the 2nd case there is already a record inserted into tbl_transaksi_detail table, therefore the calculation returns a non null value. But it returns the correct values only because the 1st and 2nd records' details are exactly the same.
I do not really understand that select that calculates id_toko anyway. If that is a transaction id, then you may use last_insert_id() if it is auto increment and the transaction record has just been created or max(id_toko) to get the highest value of id_toko (this is not multi user safe).
it seem i have mistaken select query in function set_Harga_Unit, based on clues from #Shadow
SET
id_toko =(
SELECT DISTINCT
`tbl_transaksi`.`id_toko`
FROM
`tbl_transaksi`,
`tbl_transaksi_detail`<<== I DON'T NEED THIS
WHERE
`tbl_transaksi`.`no_transaksi` = no_trans
); IF unit = "PCS" THEN
when first insert in tbl_transaksi_detail, the value no_transaksi is null because i use trigger before insert in empty table (tbl_transaksi_detail), so i remove tbl_transaksi_detail from query
SET
id_toko =(
SELECT DISTINCT
`tbl_transaksi`.`id_toko`
FROM
`tbl_transaksi`
WHERE
`tbl_transaksi`.`no_transaksi` = no_trans
); IF unit = "PCS" THEN
now it working, thanks everybody!

change one table data when single column all data of another table is equal to some value in mysql

I have created 2 tables named snag_list and defect_list. I need to change the status field of snag_list to 2 when all the defect_list status should to be 2
Not sure if this helps but try to create a trigger for defect_list
and check the distinct count of status column if it is one and the value is 2 then update the snag_list a example would look like this
DELIMITER $$
CREATE TRIGGER checkstatus
AFTER UPDATE ON defect_list
FOR EACH ROW
BEGIN
DECLARE cnt INT
SELECT COUNT(DISTINCT status) FROM defect_list INTO cnt
DECLARE st INT
SELECT DISTINCT status FROM defect_list LIMIT 1 INTO st
IF(cnt = 1 AND st = 2)
UPDATE snag_list SET status = 2
ENF IF
END$$
DELIMITER ;
Your question is very vague but I guess this is what you may be looking for.
DECLARE
count_rec VARCHAR2(10);
data_rec VARCHAR2(10);
BEGIN
SELECT COUNT(DISTINCT status) INTO count_rec FROM defect_list;
SELECT DISTINCT status INTO data_rec FROM defect_list;
IF (count_rec = '1' AND data_rec = '2') THEN
UPDATE snag_list SET status = '2';
END IF;
END;
edit -> You can change the datatype of the 2 variables as required. Go with VARCHAR2 if you're unsure whether the data would be numeric.

MYSQL multiple Triggers

I have a MYSQL table and two of the fields are called Rate_per_unit and Cost. First I want the field Rate_per_unit to populate itself from another table called SHD_TEACHER then I want the field COST to populate itself also from RATE in SHD_TEACHER and multiplies by UNITS.
I have the following code which is giving me an error:
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
SET NEW.RATE_PER_UNIT =
(
SELECT RATE
FROM SHD_TEACHER
WHERE TEACHERID = NEW.TEACHER_ID
LIMIT 1
)
SET NEW.COST = (
SELECT RATE
FROM SHD_TEACHER
WHERE TEACHERID = NEW.TEACHER_ID
) * UNITS
Any help please?
thanks
using your syntax, I would expect a delimiter statement and a begin/end block. So, try this:
DELIMITER $$
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
BEGIN
SET NEW.RATE_PER_UNIT =
(
SELECT RATE
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
LIMIT 1
)
SET NEW.COST = (
SELECT t.RATE
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
) * NEW.UNITS
END $$
DELIMITER ;
You have a limit 1 in the first subquery, suggesting that there might be multiple matches. If so, you will get a run-time error in the second. Also, UNITS is just hanging out there, all alone. I assumed it is in the NEW record.
Here is another way to write this:
DELIMITER $$
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
BEGIN
SELECT NEW.RATE_PER_UNIT := t.RATE, NEW.COST := t.RATE * NEW.UNITS
FROM (SELECT t.*
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
LIMIT 1
) t
END $$
DELIMITER ;