Rewrite MySQL Trigger to Postgres - mysql

guys!
I have a trigger in MySQL database:
CREATE DEFINER="root"#"127.0.0.1" TRIGGER `tai_actions_for_active_count` AFTER INSERT ON `actions` FOR EACH ROW BEGIN
DECLARE l_isnn TINYTEXT;
IF NEW.action_type IN ('CREATION', 'VERIFICATION', 'CLOSE') THEN
SET l_isnn = IF(NEW.isnn is NULL, '*', NEW.isnn);
IF NOT NEW.action_type = 'CLOSE' THEN
INSERT INTO subscriptions.`statistics_active_count`(`service_id`, `operator_id`, `isnn`, `active_count`)
VALUES (NEW.service_id, NEW.operator_id, l_isnn, 1)
ON DUPLICATE KEY UPDATE active_count = active_count + 1;
ELSE
SET #tai_actions_for_active_count = -1;
UPDATE subscriptions.`statistics_active_count` SET active_count = #tai_actions_for_active_count := active_count - 1
WHERE `service_id` = NEW.service_id AND `operator_id` = NEW.operator_id AND `isnn` = l_isnn;
IF #tai_actions_for_active_count = 0 THEN DELETE FROM subscriptions.`statistics_active_count` WHERE `active_count` = 0; END IF;
END IF;
END IF;
END
So I need to rewrite it to make it works in Postgres database. As there's ON DUPLICATE KEY UPDATE I'm using Postgres version 9.5 with UPSERT (ON CONFLICT (KEY) DO UPDATE).
So I poorly know SQL language can you tell me what I'm doing wrong? There's the Postgres PL code:
DECLARE
l_isnn TEXT;
tai_actions_for_active_count INTEGER;
BEGIN
IF NEW.action_type IN ('CREATION', 'VERIFICATION', 'CLOSE') THEN
IF NEW.isnn is NULL THEN
l_isnn := '*';
ELSE
l_isnn := NEW.isnn;
END IF;
IF NOT NEW.action_type = 'CLOSE' THEN
INSERT INTO "subscriptions.statistics_active_count"(service_id, operator_id, isnn, active_count)
VALUES (NEW.service_id, NEW.operator_id, l_isnn, 1)
ON CONFLICT(active_count) DO UPDATE SET active_count = active_count + 1;
ELSE
tai_actions_for_active_count := -1;
UPDATE "subscriptions.statistics_active_count" SET active_count = active_count - 1
-- (tai_actions_for_active_count := active_count - 1)
WHERE service_id = NEW.service_id AND operator_id = NEW.operator_id AND isnn = l_isnn;
UPDATE "subscriptions.statistics_active_count" SET tai_actions_for_active_count = active_count
WHERE service_id = NEW.service_id AND operator_id = NEW.operator_id AND isnn = l_isnn;
IF tai_actions_for_active_count = 0 THEN DELETE FROM "subscriptions.statistics_active_count" WHERE active_count = 0; END IF;
END IF;
END IF;
RETURN NULL;
END;
As I want to test this trigger I'm getting an error -- relation "subscriptions.statistics_active_count" does not exist
Can you help me with that code?

Finally I've got the solution. I guess :)
BEGIN
IF NEW.action_type IN ('CREATION', 'VERIFICATION', 'CLOSE') THEN
IF NEW.isnn IS NULL THEN
l_isnn := '*';
ELSE
l_isnn := NEW.isnn;
END IF;
IF NOT NEW.action_type = 'CLOSE' THEN
BEGIN
INSERT INTO subscriptions.statistics_active_count (service_id, operator_id, isnn, active_count)
VALUES (NEW.service_id, NEW.operator_id, l_isnn, 1);
EXCEPTION WHEN unique_violation THEN
UPDATE subscriptions.statistics_active_count SET active_count = active_count + 1
WHERE service_id = NEW.service_id and operator_id=NEW.operator_id;
END;
ELSE
tai_actions_for_active_count := -1;
WITH upd AS
(UPDATE subscriptions.statistics_active_count
SET active_count = active_count - 1
WHERE service_id = NEW.service_id AND operator_id = NEW.operator_id AND isnn = l_isnn;
RETURNING active_count)
SELECT *
FROM upd INTO tai_actions_for_active_count;
IF tai_actions_for_active_count = 0 THEN
DELETE FROM public.statistics_active_count
WHERE active_count = 0;
END IF;
END IF;
END IF;
END;

Related

Result consisted of more than one row - Procedure

I got this error message:
Result consisted of more than one row
but I check my procedure again and again but I cannot find any problem:
DROP PROCEDURE IF EXISTS SP_Fetch_Returned_With_Serials;
CREATE PROCEDURE `SP_Fetch_Returned_With_Serials`()
BEGIN
DECLARE Num BIGINT UNSIGNED DEFAULT 0;
DECLARE __Product_Id bigint UNSIGNED DEFAULT NULL;
DECLARE __Serials varchar(255) DEFAULT NULL;
DECLARE done INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT product_id, serials FROM tmp_table_returned_product_serial;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
START TRANSACTION ;
SET #Document_Id = 0 ;
SET #Product_Id = 0;
SET #Payment_Amount = 0;
OPEN cur;
read_loop:
LOOP
IF done
THEN
LEAVE read_loop;
END IF;
FETCH cur INTO __Product_Id,__Serials;
CALL SP_Separate_Numeric_Values(`__Serials`);
SET #Is_Returnable = 0;
SET #Level_Id = 0;
SET #Free_Day = 0;
SET #Penalty_Percent = 0;
SET #Factor_Type_Id = 0;
SET #Currency_Id = 0;
SET #Customer_Id = 0;
SET #Factor_Id = 0;
SET #Value = 0;
SET #Real_Fee = 0;
SET #Date_At = CURRENT_DATE();
SET #Diff_Days = 0;
SET #New_Factor_Id = 0;
SET #New_Detail_Factor_Id = 0;
SET #Receipt_Remit_Type_Id = 0;
SET #Return_Penalty_Percent = 0;
SET #Return_Penalty_Price = 0;
SET #Document_Number = 0;
SELECT id INTO #Factor_Type_Id FROM Tb_Factor_Types WHERE name = 'back_sale_factor';
SELECT COUNT(NV.Number) INTO #Value FROM Numeric_Values NV;
SELECT TP.is_returnable,
TU.level_id,
currency_id,
customer_id,
VF.id,
VF.product_id,
real_fee,
date_at
INTO #Is_Returnable,#Level_Id,#Currency_Id,#Customer_Id,#Factor_Id,#Product_Id,#Real_Fee,#Date_At
FROM Vw_Factor_Master_Details VF
INNER JOIN Tb_Factor_Detail_Serials TFDS ON TFDS.detail_id = VF.detail_id
INNER JOIN Tb_Products TP ON VF.product_id = TP.id
INNER JOIN Tb_Users TU ON TU.user_id = VF.customer_id
INNER JOIN Numeric_Values NV ON NV.Number = TFDS.serial_id;
IF (#Is_Returnable)
THEN
SET #Product_Title = '';
SET #Error_Msg = '';
SELECT IFNULL(TPT.title, TP.title_en) AS title INTO #Product_Title FROM Tb_Products TP
LEFT JOIN (SELECT title, product_id FROM Tb_Product_Translations WHERE locale = #Locale) TPT
ON TP.id = TPT.product_id WHERE product_id = #Product_Id;
SELECT message INTO #Error_Msg FROM Tb_Errors WHERE error_code = 1000028 AND locale = #Locale;
SET #Error_Msg = REPLACE(#Error_Msg, ':product', #Product_Title);
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = #Error_Msg;
END IF;
SELECT DATEDIFF(CURRENT_DATE(), #Date_At) INTO #Diff_Days;
SELECT MAX(`number`) INTO Num FROM Tb_Factors WHERE year_id = #Fiscal_Year AND type = 'sale_factor';
SET Num = ifnull(Num, 0) + 1;
SELECT JSON_EXTRACT(JSON_EXTRACT(TS.value, CONCAT('$.', #Level_Id)), '$.free_day')
INTO #Free_Day
FROM Tb_Settings TS
WHERE `key` = 'returned_product';
SELECT JSON_EXTRACT(JSON_EXTRACT(TS.value, CONCAT('$.', #Level_Id)), '$.penalty_percent')
INTO #Penalty_Percent
FROM Tb_Settings TS
WHERE `key` = 'returned_product';
IF (#Diff_Days > #Free_Day)
THEN
SET #Payment_Amount = #Payment_Amount + ((#Real_Fee - (#Real_Fee * #Penalty_Percent / 100)) * #Value);
SET #Return_Penalty_Percent = #Penalty_Percent;
SET #Return_Penalty_Price = #Real_Fee * #Penalty_Percent / 100;
END IF;
IF(#New_Factor_Id = 0)
THEN
INSERT INTO Tb_Factors (type, sale_place, product_type, company_id, branch_id, cash_desk_id, type_id, year_id,
currency_id, finaler_id, signature_id, customer_id, final_at, signature_at,
reference_factor_id, creator_id, number)
VALUES ('sale_factor', 'branch', 'product', #Company, #Branch_Id, NULL, #Factor_Type_Id, #Fiscal_Year,
#Currency_Id, #Auth_User, #Auth_User, #Customer_Id, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP(),
#Factor_Id, #Auth_User, Num);
SET #New_Factor_Id = LAST_INSERT_ID();
END IF;
INSERT INTO Tb_Factor_Details (product_id, value, real_fee, fee, factor_id, creator_id, return_penalty_percent,
return_penalty_price)
VALUES (#Product_Id, #Value, #Real_Fee, #Real_Fee, #New_Factor_Id, #Auth_User, #Penalty_Percent,
#Return_Penalty_Price);
SET #New_Detail_Factor_Id = LAST_INSERT_ID();
INSERT INTO Tb_Factor_Detail_Serials (serial_id, detail_id)
SELECT NV.Number, #New_Detail_Factor_Id FROM Numeric_Values NV;
SELECT id INTO #Receipt_Remit_Type_Id FROM Tb_Receipt_Remit_Types WHERE name = 'return_of_sales';
SET #Warehouse_Id = 0;
SELECT id INTO #Warehouse_Id FROM Tb_Warehouses WHERE warehouse_branch_id = #Branch_Id LIMIT 1;
IF(#Document_Id = 0)
THEN
SELECT document_number
FROM Tb_Documents
WHERE fiscal_year_id = #Fiscal_Year
ORDER BY document_number DESC
LIMIT 1
INTO #Document_Number;
SET #Document_Number = #Document_Number + 1;
INSERT INTO Tb_Documents (type, factor_id, warehouse_id, receipt_remit_type_id, fiscal_year_id, document_number,
creator_id)
VALUES ('receipt', #New_Factor_Id, #Warehouse_Id, #Receipt_Remit_Type_Id, #Fiscal_Year, #Document_Number,
#Auth_User);
SET #Document_Id = LAST_INSERT_ID();
END IF;
INSERT INTO Tb_Document_Details (product_id, value, confirmed_at, confirmed_by, creator_id, document_id)
VALUES (#Product_Id, #Value, CURRENT_TIMESTAMP(), #Auth_User, #Auth_User, #Document_Id);
SET #Document_Detail_Id = LAST_INSERT_ID();
INSERT INTO Tb_Detail_Serial_Numbers (serial_number_id, detail_id, origin_cost_center_id, confirmed_at,
confirmed_by)
SELECT NV.Number, #Document_Detail_Id,NULL,CURRENT_TIMESTAMP(),#Auth_User FROM Numeric_Values NV;
END LOOP;
CLOSE cur;
SET #Type_Id = 0;
SELECT id INTO #Type_Id FROM Tb_Payment_Types WHERE name = 'cash' LIMIT 1;
INSERT INTO Tb_Receive_Payment (model_type, model_id, factor_id, type_id, receive_amount, payment_amount,year_id,creator_id)
VALUES ('cashdesk', NULL, #New_Factor_Id, #Type_Id, 0, #Payment_Amount,#Fiscal_Year,#Auth_User);
SET #Payment_Id = LAST_INSERT_ID();
SELECT #Factor_Id as factor_id,#Payment_Id as payment_id,#Payment_Amount as payment_amount;
COMMIT;
END

How to two used while Syntax in Mysql Procecure

I would like to write two While Syntax.
The results I expect are as follows.
when 'H'
tagName1, tagName2, tagname3
when 'D'
tagName1, tagName2, tagname3
when 'M'
tagName1, tagName2, tagname3
when 'Y'
tagName1, tagName2, tagname3
But it didn't worked....
Below is the code that I wrote, while I play it only once.
Any advice, please..
DECLARE tagList varchar(255) DEFAULT 'tagName1,tagName2,tagName3';
DECLARE tagTypeList varchar(150) DEFAULT 'H,D,M,Y';
WHILE tagTypeList != '' DO
WHILE tagList != '' DO
SET tagNameArray = SUBSTRING_INDEX(tagList, ',', 1);
SET tagTypeArray = SUBSTRING_INDEX(tagTypeList, ',', 1);
IF(tagTypeArray = 'H') THEN
SET aDate = (SELECT (DATE_ADD(nDateTime, INTERVAL -1 HOUR)));
SET ago_Y = (SELECT DATE_FORMAT(aDate,'%Y'));
SET ago_M = (SELECT DATE_FORMAT(aDate,'%m'));
SET ago_D = (SELECT DATE_FORMAT(aDate,'%d'));
SET ago_H = (SELECT DATE_FORMAT(aDate,'%H'));
SET ago_W = (SELECT DATE_FORMAT(aDate,'%w'));
ELSEIF(tagTypeArray = 'D') THEN
SET aDate = (SELECT (DATE_ADD(nDateTime, INTERVAL -1 DAY)));
SET ago_Y = (SELECT DATE_FORMAT(aDate,'%Y'));
SET ago_M = (SELECT DATE_FORMAT(aDate,'%m'));
SET ago_D = (SELECT DATE_FORMAT(aDate,'%d'));
SET ago_H = 0;
SET ago_W = 0;
ELSEIF(tagTypeArray = 'M') THEN
SET aDate = (SELECT (DATE_ADD(nDateTime, INTERVAL -1 MONTH)));
SET ago_Y = (SELECT DATE_FORMAT(aDate,'%Y'));
SET ago_M = (SELECT DATE_FORMAT(aDate,'%m'));
SET ago_D = 0;
SET ago_H = 0;
SET ago_W = 0;
ELSEIF(tagTypeArray = 'Y') THEN
SET aDate = (SELECT (DATE_ADD(nDateTime, INTERVAL -1 YEAR)));
SET ago_Y = (SELECT DATE_FORMAT(aDate,'%Y'));
SET ago_M = 0;
SET ago_D = 0;
SET ago_H = 0;
SET ago_W = 0;
END IF;
SET selectValue = (SELECT tagvalue FROM datasource WHERE tagname = tagNameArray and tagtype = tagTypeArray and y=ago_Y and m=ago_M and d=ago_D and h=ago_H);
IF(selectValue IS NULL OR selectValue = '')
THEN
SET old_Value_3M = (Select LastValue from BwAnalogTable where TagName = tagNameArray and LogDate >= ago_3M order by LogDate desc, LogTime desc limit 1);
# Here Insert Querty
END IF;
IF LOCATE(',', tagList) > 0 THEN
SET tagList = SUBSTRING(tagList, LOCATE(',', tagList) + 1);
ELSE
SET tagList = '';
END IF;
END WHILE;
IF LOCATE(',', tagTypeList) > 0 THEN
SET tagTypeList = SUBSTRING(tagTypeList, LOCATE(',', tagTypeList) + 1);
ELSE
SET tagTypeList = '';
END IF;
END WHILE;
I have modified the code as shown below.
DECLARE done INT DEFAULT FALSE;
DECLARE tagType2 VARCHAR(255) DEFAULT '';
DECLARE tagName2 VARCHAR(255) DEFAULT '';
DECLARE tagType_Cur CURSOR for select tagType from tbtagtype;
DECLARE tagName_Cur CURSOR for select tagName from tbtaglist;
OPEN tagType_Cur;
LOOP1: LOOP
FETCH tagType_Cur INTO tagType2;
IF done THEN
CLOSE tagType_Cur;
LEAVE LOOP1;
END IF;
########## here insert your core query ###############
OPEN tagName_Cur;
LOOP2: LOOP
FETCH tagName_Cur INTO tagName2;
IF done THEN
CLOSE tagName_Cur;
SET done = FALSE;
LEAVE LOOP2;
END IF;
########## here insert your core query ###############
END LOOP LOOP2;
END LOOP LOOP1;

How to get data from table to variable with select in event?

I have the event
CREATE EVENT `start_insert_record_to_inout` ON SCHEDULE EVERY 10 SECOND STARTS '2014-07-12 12:07:00'
ON COMPLETION PRESERVE
ENABLE
COMMENT 'comment'
DO BEGIN
DECLARE `_count` INT DEFAULT 0;
DECLARE `_done` INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _done = 1;
SELECT `count` INTO `_count`
FROM state_execution
WHERE name = 'insert_record_to_inout' AND `type` = 'event'
LIMIT 1;
-- AND `type` = 'event';
IF _done THEN
INSERT INTO state_execution (`name`, `type`, `isUsed`,`count`) VALUES ('insert_record_to_inout', 'event','0',0);
END IF;
IF `_count` < 50 THEN
IF _done THEN
SET `_count` = 1;
SET _done = 0;
ELSE
SET `_count` = `_count` + 1;
END IF;
UPDATE state_execution SET `count` = `_count`
WHERE name = 'insert_record_to_inout' AND `type` = 'event';
call insert_record_to_inout();
SELECT `count` INTO `_count`
FROM state_execution
WHERE name = 'insert_record_to_inout' AND `type` = 'event'
LIMIT 1;
IF _done THEN
SET `_count` = 0;
ELSE
SET `_count` = `_count` - 1;
END IF;
UPDATE state_execution SET `count` = `_count` WHERE name = 'insert_record_to_inout' AND `type` = 'event';
END IF;
END
But this code
SELECT `count` INTO `_count`
FROM state_execution
WHERE name = 'insert_record_to_inout' AND `type` = 'event'
LIMIT 1;
not working. Please help me, thanks.

MySQL - trigger on before insert + if data already exists + enum column

I am working on a trigger that I though is quite easy and should work but it is not working.
Here is the (abstract) table structure:
PK_id | FK1_id | FK2_id | status
1 | 12 | 15 | 'ok'
status column is defined as enum('ok', 'ok_2', 'not_ok') NUT NULL with no default value.
The trigger should verify that a combination of both FKx_id values already exists and if yes it should set the status to 'ok_2', otherwise to 'ok' and if the status is set in the INSERT INTO it is not touched.
The trigger I have right now (only body!):
BEGIN
DECLARE cnt INT;
SET cnt = (SELECT COUNT(*) FROM `table` WHERE `FK1_id` = NEW.FK1_id AND `FK2_id` = NEW.FK2_id);
IF cnt > 0 AND NEW.status IS NULL THEN
SET NEW.status = 'ok_2';
ELSEIF NEW.status IS NULL THEN
SET NEW.status = 'ok';
END IF;
END
Unfortunately this trigger sets the status always to 'ok' - please notice that the status is not part of the INSERT query (thus considered as NULL). I have previously tried this trigger body with the same result:
BEGIN
IF (SELECT COUNT(*) FROM `table` WHERE `FK1_id` = NEW.FK1_id AND `FK2_id` = NEW.FK2_id) > 0 AND NEW.status IS NULL THEN
SET NEW.status = 'ok_2';
ELSEIF NEW.status IS NULL THEN
SET NEW.status = 'ok';
END IF;
END
and also this (with the very same result):
BEGIN
IF EXISTS(SELECT * FROM `table` WHERE `FK1_id` = NEW.FK1_id AND `FK2_id` = NEW.FK2_id LIMIT 1) AND NEW.status IS NULL THEN
SET NEW.status = 'ok_2';
ELSEIF NEW.status IS NULL THEN
SET NEW.status = 'ok';
END IF;
END
Can anyone tell me why the first condition is never met even if I am inserting the same FKx_id combination that is already present in the table?
EDIT: I switched the condition and the result is also the same - no 'ok_2' status set:
BEGIN
DECLARE cnt INT;
SET cnt = (SELECT COUNT(*) FROM `table` WHERE `FK1_id` = NEW.FK1_id AND `FK2_id` = NEW.FK2_id);
IF cnt = 0 AND NEW.status IS NULL THEN
SET NEW.status = 'ok';
ELSEIF NEW.status IS NULL THEN
SET NEW.status = 'ok_2';
END IF;
END
Got it.
The problem was this declaration of the status column:
status enum('ok', 'ok_2', 'not_ok') NOT NULL
which leads into status being pre-filled with the first enum's value if the status is not set in the INSERT statement. So the solution is next trigger body:
BEGIN
DECLARE cnt INT;
SET cnt = (SELECT COUNT(*) FROM `table` WHERE `FK1_id` = NEW.FK1_id AND `FK2_id` = NEW.FK2_id);
IF cnt = 0 THEN
SET NEW.status = 'ok';
ELSEIF NEW.status = 'ok' THEN
SET NEW.status = 'ok_2';
END IF;
END
Now if I do this insert for the first time
INSERT INTO table (FK_1, FK_2) VALUES (100, 150)
the status is 'ok', if I insert this for the second time
INSERT INTO table (FK_1, FK_2) VALUES (100, 150)
the status is 'ok_2' and if I set the status explicitly like this:
INSERT INTO table (FK_1, FK_2, status) VALUES (100, 150, 'not_ok')
the status is 'not_ok'.
so, when working with enums that have no default value while are set as NOT NULL - do not expect them to be NULL on insert when omitted. The will be pre-filled probably with the first enums's value.

Mysql Function returning same value

I am in need of mysql function but gives same value every time
this mysql function gives me same value every time i.e. S_Start_ToBeStarted (Value of 1st If)
-- colorA
DELIMITER $$
DROP FUNCTION IF EXISTS `colorA`$$
CREATE FUNCTION `colorA`(
Appf VARCHAR(3),
Start_Datef DATETIME,
PDCf DATETIME
) RETURNS INT
DETERMINISTIC
BEGIN
DECLARE finalcolor INT DEFAULT 0;
IF Appf = 'Yes' & IFNULL(Start_Datef, 'NULL' = 'NULL' & sysdate() <= PDCf
THEN SET finalcolor = (SELECT `PP_Colors`.`S_Start_ToBeStarted` FROM `SCR_Sap`.`PP_Colors` LIMIT 1);
ELSE IF Appf = 'Yes' & IFNULL(Start_Datef, 'NULL') = 'NULL' & sysdate() > PDCf
THEN SET finalcolor = (SELECT `PP_Colors`.`S_Start_Error` FROM `SCR_Sap`.`PP_Colors` LIMIT 1);
ELSE IF Appf = 'Yes' & IFNULL(Start_Datef, 'NULL') != 'NULL' & sysdate() <= PDCf
THEN SET finalcolor = (SELECT `PP_Colors`.`S_Start_Ok` FROM `SCR_Sap`.`PP_Colors` LIMIT 1);
ELSE IF Appf = 'Yes' & IFNULL(Start_Datef, 'NULL') != 'NULL' & sysdate() > PDCf
THEN SET finalcolor = (SELECT `PP_Colors`.`S_Start_LateStarted` FROM `SCR_Sap`.`PP_Colors` LIMIT 1);
ELSE SET finalcolor = (SELECT `PP_Colors`.`S_NotApplicable` FROM `SCR_Sap`.`PP_Colors` LIMIT 1);
END IF;
END IF;
END IF;
END IF;
RETURN finalcolor;
END$$
DELIMITER ;
Null doesn't work well with = and != operators, the result of foobar=NULL is NULL (unknown) not true or false. Use IS NULL and IS NOT NULL instead