IN clause not working in WHERE condition in MYSQL Trigger - mysql

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
)
);

Related

Insert into a table from multiple tables which are alike in Pattern

I have 1900 tables like table_1, table_2 and ........... which structure are same.
I want to insert all data to a new table table_all.
I know using UNION ALL I can do that but that's no useful as number of tables are large.
I made a procedure and it's working fine.
DROP PROCEDURE IF EXISTS insert_from_multiple_table;
CREATE PROCEDURE insert_from_multiple_table()
Begin
DECLARE tableCount INT DEFAULT 0;
SELECT COUNT(*)
INTO tableCount
FROM information_schema.TABLES where table_name like 'table_%' and table_Schema='your_db';
WHILE tableCount>0 DO
SET #dt_ncv = CONCAT("table_",tableCount);
SET #cntstmt = CONCAT( "insert into alltable select * FROM ",#dt_ncv);
#select #cntstmt;
PREPARE ncv_count_stmt FROM #cntstmt;
EXECUTE ncv_count_stmt;
SET tableCount = tableCount-1;
END WHILE ;
END

converting a mySQL Trigger, to TSQL

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

MYSQL Stored Procedure only updates on record

MYSQL Stored Procedure only updates one record when it should update all the ids in the WHERE id IN clause. When I run the SELECT and UPDATE outside of the stored procedure it works fine. Any suggestions?
DELIMITER $$
CREATE PROCEDURE update_ids(IN source int(10),IN target int(10))
BEGIN
DECLARE idList varchar(5000) DEFAULT NULL;
SET idList = (SELECT GROUP_CONCAT(id SEPARATOR ', ') FROM myTable ii WHERE ii.generic_id = source);
UPDATE myTable i SET i.generic_id = target WHERE i.id IN (idList);
END$$
DELIMITER ;
Then I call it by -->
CALL update_generic_ids(63, 1258);
Update : 1 row effected.
Thanks in advance,
once try below chunk of code, hope it will solve your problems!
If any question reach me!
DELIMITER $$
CREATE PROCEDURE update_ids(IN source int(10),IN target int(10))
BEGIN
DECLARE idList varchar(5000) DEFAULT NULL;
--SET idList = (SELECT GROUP_CONCAT(id SEPARATOR ', ') FROM myTable ii WHERE ii.generic_id = source);
UPDATE myTable i SET i.generic_id = target WHERE i.id IN (
SELECT id FROM myTable ii WHERE ii.generic_id = source
);
END$$
DELIMITER ;
Actually, as per my comments, I think is may be the answer..
There's a world of difference between these two queries:
UPDATE a SET b = c WHERE d IN ('1,2,3,4')
UPDATE a SET b = c WHERE d IN (1,2,3,4)
I'd recommend you amend your procedure so you're not storing your list of ids in a string variable. Actually you shouldn't need to store anything, just put the list generated by the select into the update:
UPDATE myTable i SET i.generic_id = target
WHERE i.id IN
(SELECT id SEPARATOR FROM myTable ii WHERE ii.generic_id = source);

SQL - Insert or Update with a result from another table

I have two tables DailyVisits and TotalSum My goal is to add DailyVisits to TotalSum with a stored procedure/query that I'll run at the end of the day.
DailyVisits
UserId,PageId,Visits
1,1,32
2,123,34
4,12,213
5,1,1
TotalSum
UserId,PageId,TotalVisits
1,1,300
1,41,2
3,12,213
5,1,653
and so on.
I tried two approaches but I can't get my head around a solution.
Below my queries to achieve this, if you have another suggestion/query simple enough to understand, I appreciate your help.
Approach1:
delimiter $$
CREATE PROCEDURE UPSERT_DAILYSUM()
BEGIN
IF EXISTS (SELECT Id, PageId FROM DailyVisits) THEN
UPDATE TotalSum TotalVisits = TotalVisits + (SELECT Visits FROM DailyVisits);
ELSE INSERT INTO TotalSum (UserId,PageId,TotalVisits)
VALUES (SELECT Id,PageId,Visits);
END IF
END $$
delimiter ;
Approach2:
INSERT INTO TotalSum (UserId,PageId,TotalVisits) VALUES(SELECT * FROM DailyVisits)
ON DUPLICATE KEY UPDATE (PageId,TotalVisits)
VALUES(SELECT PageId,Visits FROM DailyVisits)
This is what I'm struggling with: How will I get distinct values when key does not exist? Can I use RIGHT JOIN (or LEFT JOIN) and check for NULL values, and then add right (or left) table?
same as you need like this:
The problem is i dont know what you want to do in update and insert portion:
delimiter $$
CREATE PROCEDURE UPSERT_DAILYSUM()
BEGIN
Declare idvar int(50) DEFAULT 0;
Declare pageidvar int(50) DEFAULT 0;
SELECT Id, PageId INTO idvar,pageidvar FROM DailyVisits;
if(LENGTH(idvar)>0 THEN
UPDATE TotalSum TotalVisits = TotalVisits + (SELECT Visits FROM DailyVisits);
ELSE
INSERT INTO TotalSum (UserId,PageId,TotalVisits) VALUES (SELECT Id,PageId,Visits);
END $$
delimiter ;

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 ;