MySQL TRIGGER with an IF statement determined by an IN - mysql

I'am constructing a trigger
CREATE TRIGGER `address_control_update` BEFORE UPDATE ON `orders_shipping`
FOR EACH ROW
BEGIN
SET #error_msg_id := (SELECT `error_msg_id` FROM `orders_err` WHERE orderID = OLD.orderID);
IF(LENGTH(NEW.ShippingName) = 0 OR NEW.ShippingName IS NULL) THEN
INSERT INTO `orders_err` (orderID,error_msg_id) VALUES(NEW.orderID,100) ON DUPLICATE KEY UPDATE complete=false;
ELSEIF (100 IN (SELECT #error_msg_id)) THEN
UPDATE `orders_err` SET complete = true WHERE orderID = OLD.orderID AND error_msg_id = 100;
END IF;
END;//
Where I would like to, first see if there is any error_msg_id on the orderID and later use this in the elseif statement to see if a possible error has been completed.
It works if i do this
IF(LENGTH(NEW.ShippingName) = 0 OR NEW.ShippingName IS NULL) THEN
INSERT INTO `orders_err` (orderID,error_msg_id) VALUES(NEW.orderID,100) ON DUPLICATE KEY UPDATE complete=false;
ELSEIF EXISTS(SELECT * FROM orders_err WHERE orderID = OLD.orderID AND error_msg_id = 100) THEN
UPDATE `orders_err` SET complete = true WHERE orderID = OLD.orderID AND error_msg_id = 100;
END IF;
But i would like to only call the select once if possible, since i have 12 similar if statements on other columns in the orders_shipping table.
On update i get the error: ERROR 1242: 1242: Subquery returns more than 1 row
Thanks in advance

One of possible solutions is to concatenate ids to one string separated by commas using GROUP_CONCAT(..) function - then first SELECT statement will return one row. To test whether an id is in the string use FIND_IN_SET(..) function:
CREATE TRIGGER `address_control_update` BEFORE UPDATE ON `orders_shipping`
FOR EACH ROW
BEGIN
SET #error_msg_ids = (
SELECT GROUP_CONCAT(DISTINCT `error_msg_id`)
FROM `orders_err`
WHERE orderID = OLD.orderID
GROUP BY orderID);
IF(LENGTH(NEW.ShippingName) = 0 OR NEW.ShippingName IS NULL) THEN
INSERT INTO `orders_err` (orderID,error_msg_id) VALUES(NEW.orderID,100) ON DUPLICATE KEY UPDATE complete=false;
ELSEIF (FIND_IN_SET(100, #error_msg_ids)) THEN
UPDATE `orders_err` SET complete = true WHERE orderID = OLD.orderID AND error_msg_id = 100;
END IF;
END;//
Also I think there exists other possibilities. For example you can write code without SELECT statement:
IF(LENGTH(NEW.ShippingName) = 0 OR NEW.ShippingName IS NULL) THEN
INSERT INTO `orders_err` (orderID,error_msg_id) VALUES(NEW.orderID,100) ON DUPLICATE KEY UPDATE complete=false;
ELSE
UPDATE `orders_err` SET complete = true WHERE orderID = OLD.orderID AND error_msg_id = 100;
END IF;
why - because you use the same filtering conditions in SELECT and in UPDATE - so there no need to test the same conditions before update.

Related

Invalid use of group function. Error Code 1111

I am trying to write a procedure that makes an update to the table by adding a column that is foreign key, but returns error. What could be wrong?
DROP PROCEDURE IF EXISTS tbl_file_add_column_instance_id;
DELIMITER //
CREATE PROCEDURE tbl_file_add_column_instance_id()
BEGIN
IF NOT EXISTS((SELECT column_name FROM information_schema.columns
WHERE table_name = 'tbl_file' AND table_schema = 'diginet2' AND column_name = 'instance_id'))
THEN
ALTER TABLE tbl_file ADD COLUMN instance_id INT NOT NULL AFTER id;
ALTER TABLE tbl_file ADD CONSTRAINT id_instance_arq FOREIGN KEY (`instance_id`) REFERENCES `diginet2`.`tbl_instance` (`id`)
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- Set rows that already exist
SET #query_initial_instance := (SELECT #initial_instance:=id FROM diginet.tbl_instance WHERE instance_status = 1 LIMIT 1);
IF COUNT(#query_initial_instance) = 1
THEN
UPDATE tbl_file SET instance_id = #initial_instance;
ELSE
-- fake throw error
SELECT * FROM diginet_has_none_or_more_than_one_instance;
END IF;
END IF;
END //
DELIMITER ;
CALL tbl_file_add_column_instance_id();
and I am getting this error: Error Code 1111. Invalid use of group function
If you want to know how many rows match the WHERE condition, you should use COUNT() in the query, not the IF statement.
SET #row_count = (SELECT COUNT(*) FROM diginet.tbl_instance WHERE instance_status = 1)
IF #row_count = 1
THEN
UPDATE tbl_file SET instance_id = (SELECT id FROM digitnet.tbl_instance WHERE intance_status = 1);
ELSE
-- fake throw error
SELECT * FROM diginet_has_none_or_more_than_one_instance;
END IF
I don't think there's a legal way to get the count and the sole value in a single query. You could do:
SELECT #row_count := COUNT(*), #initial_instance:=id FROM diginet.tbl_instance WHERE instance_status = 1;
But this violates the ONLY_FULL_GROUP_BY rule.

Select into statement for null or more than one value

I am stuck in plsql , as I have making function in which I have to update a table if only values comes in select into ..
and if not come then not and if multiple comes then have to update and delete for all that values .
In below function if in first select into null value comes then should not goto exception handling should update only CUSTOMER table and only delete from table 3 ,, if one or many values comes then do all update and delete for each value
create or replace FUNCTION FUNCTION_NAME (
from_PARTICIPANT_KEY1 IN NUMBER
)
RETURN
IS
to_participant_key1 NUMBER (11);
BEGIN
SELECT to_participant_key
INTO to_participant_key1
FROM TABLE2
WHERE FROM_PARTICIPANT_KEY = from_PARTICIPANT_KEY1;
UPDATE CUSTOMERS C
SET C.CUSTOMER_STATUS_CD =
NVL (
(SELECT old_status_cd
FROM TABLE1
WHERE PARTICIPANT_UID = from_PARTICIPANT_KEY1
AND participant_cd = 'CUSTOMER'),
C.CUSTOMER_STATUS_CD
)
WHERE C.CUSTOMER_UID = from_PARTICIPANT_KEY1;
UPDATE subscribers C
SET C.STATUS_CD =
NVL (
(SELECT old_status_cd
FROM TABLE1
WHERE PARTICIPANT_UID = to_participant_key1
AND participant_cd = 'SUBSCRIBER'),
C.STATUS_CD
)
WHERE C.account_no = to_participant_key1;
DBMS_OUTPUT.PUT_LINE ('Delete TABLE1 rows');
DELETE FROM TABLE3
WHERE PARTICIPANT_UID = from_PARTICIPANT_KEY1 AND participant_cd = 'CUSTOMER';
DELETE FROM TABLE1
WHERE PARTICIPANT_UID = to_PARTICIPANT_KEY1 AND participant_cd = 'SUBSCRIBER';
COMMIT;
EXCEPTION -- exception handlers begin
WHEN NO_DATA_FOUND THEN -- handles 'division by zero' error
dbms_output.put_line('Customer not found ' || from_PARTICIPANT_KEY1);
WHEN OTHERS THEN -- handles all other errors
dbms_output.put_line('Some other kind of error occurred.');
END;
You can use BULK COLLECT INTO and iterate over collection.
First of all, you have to declare (or use some existing) collection type and create the variable of this type:
TYPE participant_keys is table of number (11);
l_participant_keys participant_keys;
Then, your query will change to:
SELECT to_participant_key
BULK COLLECT INTO to_participant_key1
FROM TABLE2
WHERE FROM_PARTICIPANT_KEY = from_PARTICIPANT_KEY1;
If the query will not return any record then you can check it with COUNT:
if l_participant_keys.COUNT = 0 then
-- update only CUSTOMER table and only delete from table 3
else
FOR I IN l_participant_keys.FIRST .. l_participant_keys.LAST LOOP
--use l_participant_keys(i) do all update and delete for each value
END LOOP;
end if;

trigger mysql unknown table

I've been trying to solve this problem. Here is the code:
CREATE TRIGGER some_trigger AFTER UPDATE ON table_a
FOR EACH ROW BEGIN
DECLARE tname VARCHAR(20);
IF (table_a.field_offer=1) THEN
SET tname='table_b';
ELSEIF (table_a.field_offer=0) THEN
SET tname='table_c';
END IF;
IF ((new.field_state = 0)) THEN
UPDATE tname join table_a on tname.ID=table_a.ref_field
SET tname.STOCK = tname.STOCK -1;
ELSEIF ((new.field_state = 1)) THEN
UPDATE tname join table_a on tname.ID=table_a.ref_field
SET tname.STOCK = tname.STOCK +1;
END IF;
END;
I am getting:
Unknown table 'table_a' in field list. Field_offer and field_state can
be null.
I've shown below what was said in the comments to the question:
CREATE TRIGGER some_trigger AFTER UPDATE ON table_a
FOR EACH ROW BEGIN
DECLARE tname VARCHAR(20);
IF (NEW.field_offer=1) THEN
UPDATE `table_b`
SET STOCK = CASE NEW.field_state
WHEN 0 THEN STOCK - 1
WHEN 1 THEN STOCK + 1
ELSE STOCK
END
WHERE ID=NEW.ref_field
;
ELSEIF (NEW.field_offer=0) THEN
UPDATE `table_c`
SET STOCK = CASE NEW.field_state
WHEN 0 THEN STOCK - 1
WHEN 1 THEN STOCK + 1
ELSE STOCK
END
WHERE ID=NEW.ref_field
;
END IF;
...
Note that I changed the updates from UPDATE ... JOIN as MySQL does not allow you to change the data of the triggered table; while you were not actually updating table_a, the JOIN could have been enough for MySQL to have objected... that and the joins would've updated every row in table_b/c that had a match in table_a, not just table_a rows related to the values in or row of the trigger.

SQL Server 2008 :: Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >=

I have [ReconcileUserInformationComputed] trigger on Userinformation table
Userinformation table has below rows
[ID] ,[CompanyID] ,[Status] ,[FirstName] ,[LastName]
UserinformationComputed table has below rows
[id] ,[CompanyID] ,[law_id] ,[Status] ,[FirstName] ,[LastName]
Below is my trigger
USE [einvoice]
GO
/****** Object: Trigger [dbo].[ReconcileUserInformationComputed] Script Date: 08/27/2014 10:53:08 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[ReconcileUserInformationComputed] ON [dbo].[UserInformation] AFTER INSERT,DELETE,UPDATE
AS
IF ##ROWCOUNT = 0 -- exit trigger when zero records affected
BEGIN
RETURN
END
SET NOCOUNT ON;
IF EXISTS (SELECT * FROM INSERTED)
BEGIN
IF EXISTS (SELECT * FROM DELETED)
BEGIN
--UPDATE
UPDATE [dbo].[UserInformationComputed]
SET -- use new values from inserted
CompanyID = (SELECT CompanyID from inserted),
law_id = (SELECT ID FROM inserted),
Status = (SELECT Status FROM inserted),
FirstName = (SELECT FirstName FROM inserted),
LastName = (SELECT LastName FROM inserted),
WHERE -- use original values from deleted
law_id = (SELECT ID FROM deleted)
END
ELSE
BEGIN
--INSERT
INSERT INTO [dbo].[UserInformationComputed] (CompanyID,law_id,Status,FirstName,LastName)
SELECT CompanyID,id,Status,FirstName,LastName) FROM inserted
END
END
ELSE IF EXISTS(SELECT * FROM DELETED)
BEGIN
--DELETE
DELETE FROM [dbo].[UserInformationComputed]
WHERE law_id = (SELECT id FROM deleted)
END
when try to update multiple users on Userinformation am getting
below error
Msg 512, Level 16, State 1, Procedure ReconcileUserInformationComputed, Line 16
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I made the changes as per the answer it worked for the above trigger but same changes didnt work for another trigger
ALTER TRIGGER [dbo].[ReconcileCrossRefComputed] ON [dbo].[CrossRef] AFTER INSERT, UPDATE, DELETE
AS
IF ##ROWCOUNT = 0 -- exit trigger when zero records affected
BEGIN
RETURN
END
SET NOCOUNT ON;
IF EXISTS (SELECT * FROM INSERTED)
BEGIN
IF EXISTS (SELECT * FROM DELETED)
BEGIN
--UPDATE
UPDATE [dbo].[CrossRefComputed]
SET -- use new values from inserted
SenderId = inserted.SenderId,
ReceiverId = inserted.ReceiverId,
ForeignRef = inserted.ForeignRef,
PolicyID = inserted.PolicyID,
From inserted
WHERE -- use original values from deleted
[CrossRefComputed].SenderId = inserted.SenderId
AND [CrossRefComputed].ReceiverId = inserted.ReceiverId
END
ELSE
BEGIN
--INSERT
INSERT INTO [dbo].[CrossRefComputed] (SenderId, ReceiverId, ForeignRef, PolicyID)
SELECT SenderId, ReceiverId, Effective, PolicyID FROM inserted
END
END
ELSE IF EXISTS(SELECT * FROM DELETED)
BEGIN
--DELETE
DELETE FROM [dbo].[CrossRefComputed]
WHERE SenderId in (SELECT SenderId FROM deleted)
AND ReceiverId in (SELECT ReceiverId FROM deleted)
END
COuld anyone please help me how to fix the procedure to handle updating multiple records?
Be aware that an UPDATE or a DELETE can affect more than one record and your trigger will have to deal with them at once, in this case your "inserted" or "deleted" table will have more than one record.
You will have to use a join in your DML. Something like this:
UPDATE [dbo].[UserInformationComputed]
SET
CompanyID = inserted.CompanyID,
law_id = inserted.ID,
Status = inserted.Status,
FirstName = inserted.FirstName,
LastName = inserted.LastName
from inserted
WHERE
UserInformationComputed.law_id = inserted.ID
I haven't perfectly understood your UPDATE logic, so you'll have to adapt my code.
In your DELETE command you may have just to change "=" to "in":
DELETE FROM [dbo].[UserInformationComputed]
WHERE law_id in (SELECT id FROM deleted)
Take a look at this:
http://msdn.microsoft.com/en-us/library/ms190752.aspx

MySQL: Conditional to run Query 1 or Query 2 based on a certain field

I'm creating a trigger which is supposed to run Query 1 if the value of the field statuscode from the newly inserted row is 200. But if the statuscode is say 300 run Query 2 instead. Is this at all possible in MySQL?
I tried the first thing which came to mind but it's obviously wrong.
CREATE TRIGGER mytrigger AFTER INSERT ON tableA
FOR EACH ROW BEGIN
IF(new.statuscode = 200,
(DELETE FROM tableB WHERE new.guid = tableB.guid),
(UPDATE tableB SET is_complete = 0 WHERE new.guid = tableB.guid))
END
//
DELIMITER ;
The syntax for IF/ELSE in mysql procedures is:
IF (NEW.statuscode = 200) THEN
DELETE FROM tableB WHERE new.guid = tableB.guid;
ELSE
UPDATE tableB SET is_complete = 0 WHERE new.guid = tableB.guid;
END IF;
Here are the docs for trigger syntax:
http://dev.mysql.com/doc/refman/5.5/en/if.html
I think you just have your IF syntax wrong. If statements should have a THEN and ENDIF keyword.
http://dev.mysql.com/doc/refman/5.0/en/if.html
I haven't used MySQL in 6 months or so, so hopefully this syntax is right:
CREATE TRIGGER mytrigger AFTER INSERT ON tableA
FOR EACH ROW BEGIN
IF new.statuscode = 200 THEN
DELETE FROM tableB WHERE new.guid = tableB.guid;
ELSE
UPDATE tableB SET is_complete = 0 WHERE new.guid = tableB.guid;
END IF;
END