How to SELECT multiple values in MYSQL trigger? - mysql

how can I SELECT multiple values INTO variables in MYSQL trigger?
I have tried SELECT values into variables in this way but it didn't work. I was inspired by this thread how to use trigger to set value based on query result.
When I examined value in variables, it is NULL. When I put this SELECT into mysql workbench it will select right values. I check column types and they are same type as variables in trigger.
With debug I discovered that there is problem with SELECTing values.
Thank you in advance.
Here is my trigger:
CREATE TRIGGER fin_den_zam_insert
AFTER INSERT
ON table1 FOR EACH ROW
BEGIN
DECLARE koef1 DECIMAL(6,3);
DECLARE koef2 DECIMAL(6,3);
DECLARE koef3 DECIMAL(6,3);
DECLARE sum DECIMAL(6,3);
SELECT DISTINCT
koef_salary, koef_sunday, koef_holiday
INTO
koef1 , koef2, koef3
FROM
employee E
WHERE
E.personal_number = NEW.personal_number_id;
SET sum := NEW.salary * (koef1 + koef2 + koef3);
INSERT INTO export_table
(
id_export,
personal_number,
final_sum
)
VALUES
(
NULL,
NEW.personal_number_id,
sum
);
END;
//
DELIMITER ;

You must be careful with reserved words like sum, that can cause very much trouble-
most people write before every own variable _ like _sum, so that also a stranger can identofy such variables.
That is as you can see not absoltely necessary, but helps also when you tale a look in 5 years
create table employee
(personal_number int,koef_salary DECIMAL(6,3), koef_sunday DECIMAL(6,3), koef_holiday DECIMAL(6,3));
create table export_table(
id_export int auto_increment primary key,
personal_number int,
final_sum DECIMAL(6,3)
);
CREATE table table1
(id_export int auto_increment primary key
, personal_number_id int
, salary DECIMAL(6,3));
insert into employee values(1,1.1,1.3,1.4);
CREATE TRIGGER fin_den_zam_insert
AFTER INSERT
ON table1 FOR EACH ROW
BEGIN
DECLARE koef1 DECIMAL(6,3);
DECLARE koef2 DECIMAL(6,3);
DECLARE koef3 DECIMAL(6,3);
DECLARE final_sum DECIMAL(6,3);
SELECT DISTINCT
koef_salary, koef_sunday, koef_holiday
INTO
koef1 , koef2, koef3
FROM
employee E
WHERE
E.personal_number = NEW.personal_number_id;
SET final_sum := NEW.salary * (koef1 + koef2 + koef3);
INSERT INTO export_table
(
id_export,
personal_number,
final_sum
)
VALUES
(
NULL,
NEW.personal_number_id,
final_sum
);
END
INSERT INTO table1 VALUES (NULL,1,100)
SELECT * FROM export_table
id_export | personal_number | final_sum
--------: | --------------: | --------:
1 | 1 | 380.000
db<>fiddle here

Related

MySQL - copy or update rows with a change within one table

I have a database table like this one:
group | detailsID | price
EK | 1 | 1.40
EK | 2 | 1.50
EK | 3 | 1.60
H | 1 | 2.40
H | 2 | 2.50
Now I want to copy the data from group "EK" to the group "H", so the prices for the detailsID's must be adjusted for the detailsIDs 1 and 2, and the entry for detailsID 3 must be inserted for group "H".
How can I do that with one or two MySQL query's?
Thanks!
We can try doing an INSERT INTO ... SELECT with ON DUPLICATE KEY UPDATE:
INSERT INTO yourTable (`group`, detailsID, price)
SELECT 'H', detailsID, price
FROM yourTable t
WHERE `group` = 'EK'
ON DUPLICATE KEY UPDATE price = t.price;
But this assumes that there exists a unique key on (group, detailsID). If this would not be possible, then this approach would not work.
As an alternative, I might do this in two steps. First, remove the H group records, then insert the updated H records you expect.
DELETE
FROM yourTable
WHERE `group` = 'H';
INSERT INTO yourTable (`group`, detailsID, price)
SELECT 'H', detailsID, price
FROM yourTable
WHERE `group` = 'EK';
I use the above approach because a single update can't handle your requirement, since new records also need to be inserted.
Note that you should avoid naming your columns and tables using reserved MySQL keywords such as GROUP.
You can try this as well, Following code implemented using stored procedures. Very simple not that difficult to understand. You may need to modify data type and optimize the code as per the requirement.
DELIMITER $$;
DROP PROCEDURE IF EXISTS update_H $$;
CREATE PROCEDURE update_H()
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE `group_col` varchar(255) DEFAULT "";
DECLARE `detaildid_col` varchar(255) DEFAULT "";
DECLARE `price_col` varchar(255) DEFAULT "";
DECLARE H_FOUND INTEGER DEFAULT 0;
DECLARE pull_data CURSOR FOR select `group`, `detaildid`, `price` from test.newtab WHERE `group` = 'EK';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN pull_data;
traverse_data: LOOP
FETCH pull_data INTO group_col, detaildid_col, price_col;
IF finished = 1 THEN
LEAVE traverse_data;
END IF;
SET H_FOUND = (SELECT count(*) from test.newtab where `group` = 'H' AND `detaildid` = detaildid_col);
IF ( H_FOUND = 1 ) THEN
UPDATE test.newtab SET `price` = price_col where `group` = 'H' AND `detaildid` = detaildid_col;
ELSE
INSERT INTO test.newtab (`group`, `detaildid`, `price`) VALUES ('H', detaildid_col, price_col);
END IF;
END LOOP traverse_data;
CLOSE pull_data;
END $$;
DELIMITER ;
You can call this procedure by executing, call update_H();

IF ELSE STATEMENT for the Differnce of two columns in MYSQL

I have 3 tables : badge_master, match_result_updation and team_badges.
The badge_master is the master table where I manually insert the data acc to the excel. On match_result_updation I have some columns, if sum(goal_column1) - sum(goal_column2) = 10, then the value column1 will get the badge and it will be inserted in team_badges table. I am handling it through trigger but unable to proceed after certain time.
The trigger which I tried :
CREATE TRIGGER `afterinsert_teamgoals` AFTER INSERT ON `match_result_updation` FOR EACH ROW
BEGIN
DECLARE goalCount1 INT(10);
DECLARE goalCount2 INT(10);
DECLARE badgeId BIGINT(20);
DECLARE teamId bigint(20) default 0 ;
SELECT team1_goal INTO goalCount1 FROM match_result_updation WHERE team1_id = NEW.team1_id ;
SELECT team2_goal INTO goalCount2 FROM match_result_updation WHERE team2_id = NEW.team2_id ;
IF (goalCount1 - goalCount2 >= 10)
Then
Insert into team_badges(team_id,badge_id,match_id,timestamp)
SELECT teamId , badgeId , match_id FROM match_result_updation limit 1;
END IF;
Please Assist.

count number of hierarchical childrens in sql

I have a table that stores parent and left child and right child information. How do i count number of children belongs that parent?
for example my table structure is:
parent left right
--------------------
1 2 3
3 4 5
4 8 9
5 10 11
2 6 7
9 12 null
How do I count number of sub nodes for any parent. For example 4 contains following hierarchical child nodes - 8,9,12 so number of children are 3.
3 contains following sub nodes -> 4,5,10,11,8,9,12 so total number of children 7.
How do I achieve this using SQL query?
create table mytable
( parent int not null,
cleft int null,
cright int null
)
insert into mytable (parent,cleft,cright) values (1,2,3);
insert into mytable (parent,cleft,cright) values (2,6,7);
insert into mytable (parent,cleft,cright) values (3,4,5);
insert into mytable (parent,cleft,cright) values (4,8,9);
insert into mytable (parent,cleft,cright) values (5,10,11);
insert into mytable (parent,cleft,cright) values (6,null,null);
insert into mytable (parent,cleft,cright) values (7,null,null);
insert into mytable (parent,cleft,cright) values (8,13,null);
insert into mytable (parent,cleft,cright) values (9,12,null);
insert into mytable (parent,cleft,cright) values (10,null,null);
insert into mytable (parent,cleft,cright) values (12,null,null);
insert into mytable (parent,cleft,cright) values (13,null,17);
insert into mytable (parent,cleft,cright) values (17,null,null);
DELIMITER $$
CREATE procedure GetChildCount (IN parentID INT)
DETERMINISTIC
BEGIN
declare ch int;
declare this_left int;
declare this_right int;
declare bContinue boolean;
declare count_needs_scan int;
create temporary table asdf999 (node_id int,processed int);
-- insert into asdf999 (node_id,processed) values (1,0);
-- update asdf999 set processed=1;
SET ch = parentID;
set bContinue=true;
while bContinue DO
-- at this point you are sitting at a ch (anywhere in hierarchy)
-- as you are looping and getting/using children
-- save non-null children references: -----------------------------
select cleft into this_left from mytable where parent=ch;
if !isnull(this_left) then
insert asdf999 (node_id,processed) select this_left,0;
end if;
select cright into this_right from mytable where parent=ch;
if !isnull(this_right) then
insert asdf999 (node_id,processed) select this_right,0;
end if;
-- -----------------------------------------------------------------
select count(*) into count_needs_scan from asdf999 where processed=0;
if count_needs_scan=0 then
set bContinue=false;
else
select node_id into ch from asdf999 where processed=0 limit 1;
update asdf999 set processed=1 where node_id=ch;
-- well, it is about to be processed
end if;
END WHILE;
select count(*) as the_count from asdf999;
drop table asdf999;
END $$
DELIMITER ;
call GetChildCount(2); -- answer is 2
call GetChildCount(4); -- answer is 5
I could supply a version that creates a dynamically named table (or temp table) and clobbers it at end if you want . "dynamic sql / prepare statment" inside of a procedure. that way users won't step on each other with shared use of the work table asdf999. so this is not production ready. but the above gives you an idea of the concept

Alternative to Cursor

I am looking for an alternative way to using a cursor for a stored procedure. Instead of selecting each Database (LAL, SINC, SMSS) like I do below, I would like to select a list of strings from a separate table and insert them into the #rates table, joined with there corresponding db/table. Is there a way to do this with a join, or will I need to write this with Dynamic SQL/Cursor?
I'm looking for possible solutions and appreciate all advice. Thanks.
DECLARE #rates TABLE
(
DB CHAR(5),
FUTASUTA CHAR(3),
DSCRIPTN CHAR(31),
FUSUTXRT DECIMAL(18,4)
)
-- LAL Rates
INSERT INTO #rates
SELECT 'LAL', FUTASUTA, DSCRIPTN, (CONVERT(DECIMAL(18,4),FUSUTXRT))/10000000 as FUSUTXRT
FROM [LAL].[dbo].[UPR40100]
-- SINC Rates
INSERT INTO #rates
SELECT 'SINC', FUTASUTA, DSCRIPTN, (CONVERT(DECIMAL(18,4),FUSUTXRT))/10000000 as FUSUTXRT
FROM [SINC].[dbo].[UPR40100]
-- SMSS Rates
INSERT INTO #rates
SELECT 'SMSS', FUTASUTA, DSCRIPTN, (CONVERT(DECIMAL(18,4),FUSUTXRT))/10000000 as FUSUTXRT
FROM [SMSS].[dbo].[UPR40100]
....etc
The table with Distinct databases is a simple table with names/id's
id | Name
1 | LAL
2 | SINC
3 | SMSS
etc...
Following method will work for you :
DECLARE #TABLE TABLE(DBNAME VARCHAR(50))
DECLARE #DYNAMICQUERY VARCHAR(MAX)
INSERT INTO #TABLE VALUES('LAL')
INSERT INTO #TABLE VALUES('SINC')
INSERT INTO #TABLE VALUES('SMSS')
SET #DYNAMICQUERY =
(
SELECT 'INSERT INTO #rates SELECT '''+ DBNAME +''', FUTASUTA,DSCRIPTN, (CONVERT(DECIMAL(18,4),FUSUTXRT))/10000000 as FUSUTXRT FROM ['+ DBNAME + '].[dbo].[UPR40100];'
FROM #TABLE
FOR XML PATH('')
)
EXEC(#DYNAMICQUERY)

split a column into three separate columns with a delimiter

I have values in a column in the table
For Eg: Abc-a,d,f,g,h;Acd-b,h,i,j;Asx-i,k,l,m
Now what i want is i need the values a,d,f,g,h to be copied into a separate column named 'Abc' similarly b,h,i,j to another column "Acd"(Adding clarity to the above point,i want all the comma separated values to come under a separate column and the column name will be the string which is prefixed before the '-').i should be splited using the delimiter ';'
First of all never store data as comma separated values, its a bad practice and you should always normalize the data
Now as far as your current situation is concern and if the pattern is same you can extract data as below using the substring_index() function
mysql> select substring_index(substring_index('Abc-a,d,f,g,h;Acd-b,h,i,j;Asx-i,k,l,m',';',1),'Abc-',-1) as Abc ;
+-----------+
| Abc |
+-----------+
| a,d,f,g,h |
+-----------+
mysql> select substring_index(substring_index('Abc-a,d,f,g,h;Acd-b,h,i,j;Asx-i,k,l,m',';',2),'Acd-',-1) as Acd;
+---------+
| Acd |
+---------+
| b,h,i,j |
+---------+
mysql> select substring_index(substring_index('Abc-a,d,f,g,h;Acd-b,h,i,j;Asx-i,k,l,m',';',-1),'Asx-',-1) as Asx;
+---------+
| Asx |
+---------+
| i,k,l,m |
+---------+
Finally putting all together you can have the update command as
update your_table
set
Abc = substring_index(substring_index('Abc-a,d,f,g,h;Acd-b,h,i,j;Asx-i,k,l,m',';',1),'Abc-',-1),
Acd = substring_index(substring_index('Abc-a,d,f,g,h;Acd-b,h,i,j;Asx-i,k,l,m',';',2),'Acd-',-1),
Asx = substring_index(substring_index('Abc-a,d,f,g,h;Acd-b,h,i,j;Asx-i,k,l,m',';',-1),'Asx-',-1) ;
Note that I have added the complete string in the above example, you may just add the column name where the values are stored
DECLARE #DATA NVARCHAR(MAX), #COLUMNROWCOUNT INT, #COLUMNVALUE NVARCHAR(MAX)
DECLARE #VALUEROWCOUNT INT, #VALUE NVARCHAR(MAX), #SQLQUERY NVARCHAR(MAX)
SET #DATA='Abc-a,d,f,g,h;Acd-b,h,i,j;Asx-i,k,l,m'
CREATE TABLE #TEMPCOLUMNS(
ID int IDENTITY(1,1) NOT NULL,
VALUE NVARCHAR(MAX)
)
CREATE TABLE #TEMPVALUES(
ID int IDENTITY(1,1) NOT NULL,
VALUE NVARCHAR(MAX)
)
CREATE TABLE #TEMPCOLUMNVALUE(
ID int IDENTITY(1,1) NOT NULL,
COLUMNNAME NVARCHAR(MAX),
COLUMNVALUE NVARCHAR(MAX)
)
INSERT INTO #TEMPCOLUMNS
SELECT value AS VALUE
FROM dbo.Split(#DATA, ';')
SET #COLUMNROWCOUNT=1
SET #COLUMNVALUE=''
WHILE #COLUMNROWCOUNT <=(SELECT COUNT(*) FROM #TEMPCOLUMNS)
BEGIN
SET #COLUMNVALUE=(SELECT VALUE FROM #TEMPCOLUMNS WHERE ID=#COLUMNROWCOUNT)
TRUNCATE TABLE #TEMPVALUES
INSERT INTO #TEMPVALUES
SELECT value AS VALUE
FROM dbo.Split(#COLUMNVALUE, '-')
INSERT INTO #TEMPCOLUMNVALUE SELECT
(SELECT VALUE FROM #TEMPVALUES WHERE ID=1) COLUMNNAME,
(SELECT VALUE FROM #TEMPVALUES WHERE ID=2) COLUMNVALUE
SET #COLUMNROWCOUNT=#COLUMNROWCOUNT+1
END
SET #VALUEROWCOUNT=1
SET #VALUE=''
SET #SQLQUERY='CREATE TABLE #TEMP( '
WHILE #VALUEROWCOUNT <=(SELECT COUNT(*) FROM #TEMPCOLUMNVALUE)
BEGIN
SET #VALUE=(SELECT COLUMNNAME FROM #TEMPCOLUMNVALUE WHERE ID=#VALUEROWCOUNT)
SET #SQLQUERY=#SQLQUERY+#VALUE+' NVARCHAR(MAX)'
IF (#VALUEROWCOUNT <>(SELECT COUNT(*) FROM #TEMPCOLUMNVALUE))
BEGIN
SET #SQLQUERY=#SQLQUERY+','
END
SET #VALUEROWCOUNT=#VALUEROWCOUNT+1
END
SET #SQLQUERY=#SQLQUERY+')'
SET #VALUEROWCOUNT=1
SET #VALUE=''
SET #SQLQUERY=#SQLQUERY+'INSERT INTO #TEMP SELECT '
WHILE #VALUEROWCOUNT <=(SELECT COUNT(*) FROM #TEMPCOLUMNVALUE)
BEGIN
SET #VALUE=(SELECT COLUMNVALUE FROM #TEMPCOLUMNVALUE WHERE ID=#VALUEROWCOUNT)
SET #SQLQUERY=#SQLQUERY+''''+#VALUE+''''
IF (#VALUEROWCOUNT <>(SELECT COUNT(*) FROM #TEMPCOLUMNVALUE))
BEGIN
SET #SQLQUERY=#SQLQUERY+','
END
SET #VALUEROWCOUNT=#VALUEROWCOUNT+1
END
SET #SQLQUERY=#SQLQUERY+'SELECT * FROM #TEMP DROP TABLE #TEMP'
PRINT(#SQLQUERY)
EXEC(#SQLQUERY)
DROP TABLE #TEMPCOLUMNS
DROP TABLE #TEMPVALUES
DROP TABLE #TEMPCOLUMNVALUE
SQL FUNCTION:
CREATE FUNCTION [dbo].[Split]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(100)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
END
Please try it.