TRIGGER with insert partial field - mysql

2 tables
tb_product :
product_id,
product_size_values
tb_product_category :
product_id ,
category_id
product_size_values contains '41,42,46' or '44,45,46,47' or any values from 42 to 48 with coma separator ....
and the trigger
CREATE TRIGGER trg_product_size AFTER UPDATE ON tb_product
FOR EACH ROW
BEGIN
IF (NEW.product_size_values != OLD.product_size_values) THEN
INSERT INTO tb_product_category (product_id, product_size_values)
VALUES (NEW.product_id, 42) WHERE NEW.product_size_values LIKE '%42%'
;
INSERT INTO tb_product_category (product_id, product_size_values)
VALUES (NEW.product_id, 43) WHERE NEW.product_size_values LIKE '%43%'
;
END IF;
END //
of course the WHERE NEW.product_size_values LIKE does not work
my normal query to do that actually (without trigger ) is
insert into tb_product_category (product_id,category_id)
select product_id,42
from tb_product
where product_size_values like '%42%' ;
insert into tb_product_category (product_id,category_id)
select product_id,43
from tb_product
where product_size_values like '%43%' ;
and NO the comma separated field cannot be changed
thanks for helping

I guess the problem is that you cannot use a like test in a conditional statement and you cannot use a where clause with values and an insert select seems wasteful. You may be able to ditch the like clause and use and instr or locate to check values for example
drop table if exists tb_product,tb_product_category;
create table tb_product
(product_id int,
product_size_values varchar(20));
insert into tb_product values
(1,'42');
create table tb_product_category
(product_id int,
category_id int);
drop trigger if exists trg_product_size;
delimiter $$
CREATE TRIGGER trg_product_size AFTER UPDATE ON tb_product
FOR EACH ROW
BEGIN
IF (NEW.product_size_values != OLD.product_size_values) THEN
if instr(NEW.product_size_values,42) > 0 then
INSERT INTO tb_product_category (product_id, category_id) values (new.product_id,42);
end if;
if INSTR(NEW.product_size_values,43) > 0 then
INSERT INTO tb_product_category (product_id, category_id) values (new.product_id,43);
end if;
END IF;
END $$
delimiter ;
select product_size_values from tb_product;
update tb_product
set product_size_values = '42,43' where product_id = 1;
select * from tb_product_Category;
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1 | 42 |
| 1 | 43 |
+------------+-------------+
Works as coded. You may wish to change the insert logic to check for existence before inserting to avoid duplicates.

Related

MySql error 1064 on trigger createion with if statement

Below is the code. All I want to do is check if a quote exists and, if not, insert the record into another table.
DROP TRIGGER IF EXISTS `CB2`;
CREATE TRIGGER CB2
AFTER UPDATE
ON `quotes` FOR EACH ROW
BEGIN
IF (SELECT quoteID FROM booking WHERE quoteID <> new.`quoteID`) THEN
INSERT INTO `booking`(`Book_ID`, `Date`, `CustomerID`, `CustodianID`, `cusCntNum`, `Service`, `sAddress`, `Size`, `Comments`, `Frequency`, `Duration`, `Bdrms`, `Bathrm`, `Living Spaces`, `AppointmentStartDate`, `Time`, `ServiceDay`, `AddOns`, `Fee`, `quoteID`, `uBookingID`) VALUES (NULL, CURRENT_DATE, new.CustAccNum, new.CustodianNum, new.Contact_Number, new.ServType,new.Address, new.CommercialSize, new.Comments, new.Frequency, new.Duration, new.Bedrooms, new.Bathrooms, new.lSpaces, new.AppointmentDate, new.AppointmentTime ,DAYOFWEEK(new.AppointmentTime), new.sAddOns, new.Fee, new.quoteID,'');
END IF;
END
You need DELIMITER so that mysql can identify whyt belongs to the trigger
DROP TRIGGER IF EXISTS `CB2`;
DELIMITER //
CREATE TRIGGER CB2
AFTER UPDATE
ON `quotes` FOR EACH ROW
BEGIN
IF (SELECT quoteID FROM booking WHERE quoteID <> new.`quoteID`) THEN
INSERT INTO `booking`
(`Book_ID`, `Date`, `CustomerID`, `CustodianID`, `cusCntNum`, `Service`, `sAddress`, `Size`, `Comments`, `Frequency`, `Duration`, `Bdrms`, `Bathrm`, `Living Spaces`, `AppointmentStartDate`, `Time`, `ServiceDay`, `AddOns`, `Fee`, `quoteID`, `uBookingID`) VALUES
(NULL, CURRENT_DATE, new.CustAccNum, new.CustodianNum, new.Contact_Number, new.ServType,new.Address, new.CommercialSize, new.Comments, new.Frequency, new.Duration, new.Bedrooms, new.Bathrooms, new.lSpaces, new.AppointmentDate, new.AppointmentTime ,DAYOFWEEK(new.AppointmentTime), new.sAddOns, new.Fee, new.quoteID,'');
END IF;
END//
DELIMITER ;
You do need to set delimiters but you also need an existence check. Using a simplified version of your model
drop table if exists quotes,booking;
create table quotes(quoteid int, val int);
create table booking(quoteid int,val int);
drop trigger if exists t;
delimiter $$
CREATE TRIGGER t
AFTER UPDATE
ON `quotes` FOR EACH ROW
BEGIN
insert into debug_table(msg) values (new.quoteid);
IF not exists (SELECT quoteID FROM booking WHERE quoteID = new.`quoteID`) THEN
INSERT INTO `booking`( `quoteID`,val) VALUES (new.quoteid,new.val);
END if;
end $$
delimiter ;
truncate debug_table;
insert into quotes(quoteid) values (1),(2);
update quotes set val = 10 where quoteid = 1;
update quotes set val = 20 where quoteid = 1;
MariaDB [sandbox]> select * from booking;
+---------+------+
| quoteid | val |
+---------+------+
| 1 | 10 |
+---------+------+
1 row in set (0.001 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> select * from debug_table;
+----+------+
| id | msg |
+----+------+
| 1 | 1 |
| 2 | 1 |
+----+------+
2 rows in set (0.001 sec)
You don't need the debug table but it provides proof that the trigger fired twice as expected.
BTW I'm not convinced that your logic is sound.

MySQL - Insert Into 2 Tables on 1 Procedure

I need to create a procedure for inserting records into 2 tables, but on the second table, I want to insert the last ID that was inserted on the first table. Could anyone help me with this?
This is my query
DELIMITER //
DROP PROCEDURE IF EXISTS ROOM_FEATURE_INSERT;
CREATE PROCEDURE ROOM_FEATURE_INSERT (propID INT, featID INT, featNme VARCHAR(50))
BEGIN
-- BEGIN CHECK
IF NOT EXISTS
(
SELECT rFeatureName FROM COMPANY_T3s71.PROPERTY_RFEATURE PRFE
INNER JOIN COMPANY_T3s71.ROOM_FEATURE RFEA ON PRFE.rFeatureID=RFEA.rFeatureID
WHERE BINARY rFeatureName = featNme AND propertyID = propID
)
AND
(
SELECT rFeatureName FROM COMPANY_T3s71.ROOM_VIEW
WHERE BINARY rFeatureName = featNme
)
THEN
-- IF NOT EXISTS INSERT INTO 1st TABLE
INSERT INTO COMPANY_T3s71.ROOM_FEATURE (rFeatureName) VALUES (featNme);
END IF;
-- END CHECK
-- BEGIN CHECK 2nd TABLE
IF NOT EXISTS
(
SELECT propertyID, rFeatureID FROM COMPANY_T3s71.PROPERTY_RFEATURE
WHERE rFeatureID = featID AND propertyID = propID
)
THEN
-- IF NOT EXISTS INSERT INTO 2nd TABLE
INSERT INTO COMPANY_T3s71.PROPERTY_RFEATURE (propertyID, rFeatureID) VALUES (propID, featID);
END IF;
-- END CHECK 2nd TABLE
END
DELIMITER ;
How do we pass the featID param, when we just inserted it on the first INSERT query?
Thank you before hand.
Use SET featID = LAST_INSERT_ID(); after the first query and then use the variable
INSERT INTO COMPANY_T3s71.ROOM_FEATURE (rFeatureName) VALUES (featNme);
SET featID = LAST_INSERT_ID();
However, if the data is not insert at anytime then you have to make query in the if block to set the value for featID.

Create a trigger to insert the old data to a new table

Here is the table I created.
USE my_guitar_shop;
DROP TABLE IF EXISTS Products_Audit;
CREATE TABLE Products_Audit (
audit_id INT PRIMARY KEY,
category_id INT REFERENCES categories(category_id),
product_code VARCHAR ( 10 ) NOT NULL UNIQUE ,
product_name VARCHAR ( 255 ) NOT NULL,
list_price INT NOT NULL,
discount_percent INT NOT NULL DEFAULT 0.00 ,
date_updated DATETIME NULL);
Create a trigger named products_after_update. This trigger should insert the old data about the product into the Products_Audit table after the row is updated. Then, test this trigger with an appropriate UPDATE statement.
Here is the trigger I created but the data is not showing up in the Products_Audit table it is showing all null.
USE my_guitar_shop;
DROP TRIGGER IF EXISTS products_after_update;
DELIMITER $$
CREATE TRIGGER products_after_update
BEFORE UPDATE ON products
FOR EACH ROW
BEGIN
INSERT INTO products_audit (audit_id, product_id, category_id, product_code,
product_name, list_price, discount_percent, date_updated)
SELECT audit_id, products.product_id, products.category_id, products.product_code,
products.product_name,products.list_price, products.discount_percent, date_updated
FROM products JOIN products_audit
ON products_audit.audit_id = (SELECT audit_id FROM inserted);
END $$
DELIMITER ;
EDIT with the INSERT INTO
USE my_guitar_shop;
DROP TRIGGER IF EXISTS products_after_update;
DELIMITER $$
CREATE TRIGGER products_after_update
BEFORE UPDATE ON products
FOR EACH ROW
BEGIN
INSERT INTO products_audit (audit_id, product_id, category_id,product_code,
product_name, list_price, discount_percent, date_updated)
VALUES (OLD.audit_id, OLD.product_id, OLD.category_id, OLD.product_code,
OLD.product_name, OLD.list_price, OLD.discount_percent, OLD.date_updated)
DELIMITER ;
You are overcomplicating the insert. As mysql documentation on triggers says:
In an UPDATE trigger, you can use OLD.col_name to refer to the columns
of a row before it is updated and NEW.col_name to refer to the columns
of the row after it is updated.
Therfore, use the OLD.column_name format in the insert. Also, I would set the audit_id field to auto increment and leave it out of the insert:
INSERT INTO products_audit (product_id, category_id, product_code,
product_name, list_price, discount_percent, date_updated)
VALUES (OLD.product_id, OLD.category_id, OLD.product_code,
OLD.product_name, OLD.list_price, OLD.discount_percent, OLD.date_updated)
Here's an example of how I do it:
CREATE OR REPLACE EDITIONABLE TRIGGER E_TABLE_TRG
before insert or update or delete on e_table
for each row
declare
l_seq number;
begin
-- Get a unique sequence value to use as the primary key
select s_seq.nextval
into l_seq
from dual;
if inserting then
:new.date_opened := sysdate;
:new.last_txn_date := null;
:new.status := 'A';
end if;
if inserting then
insert into e_table_history
(
t_seq,
user_id,
date_opened,
last_txn_date,
status,
insert_update_delete,
insert_update_delete_date
)
values
(
l_seq,
:new.user_id,
:new.date_opened,
:new.last_txn_date,
:new.status,
'I',
sysdate
);
elsif updating then
insert into e_table_history
(
t_seq,
date_opened,
last_txn_date,
status,
insert_update_delete,
insert_update_delete_date
)
values
(
l_seq,
:new.date_opened,
:new.last_txn_date,
:new.status,
'U',
sysdate
);
else
insert into e_table_history
(
t_seq,
date_opened,
last_txn_date,
status,
insert_update_delete,
insert_update_delete_date
)
values
(
l_seq,
:old.date_opened,
:old.last_txn_date,
:old.status,
'D',
sysdate
);
end if;
end;
/
ALTER TRIGGER E_TABLE_TRG ENABLE;
/

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

mysql trigger error with 2 conditions

I want to add an after insert trigger which will do the following.
The first IF condition works normally, but when it comes to the second everything stops.
Any ideas?
USE `Syslog`;
DELIMITER $$
CREATE TRIGGER `SystemEventsR_AINS` AFTER INSERT ON SystemEventsR FOR EACH ROW
IF
(exists
(select syslogtag from SystemEventsRcounter where syslogtag=
new.syslogtag)
AND
(select simpledate from SystemEventsRcounter
where syslogtag=new.syslogtag)=new.simpledate)
THEN
UPDATE SystemEventsRcounter
SET records=records+1
WHERE SystemEventsRcounter.syslogtag=new.syslogtag;
ELSE INSERT SystemEventsRcounter (simpledate, syslogtag, records) values (new.simpledate,new.syslogtag,1);
END IF
UPDATED:
What you need is INSERT INTO ... ON DUPLICATE KEY.
CREATE TRIGGER `SystemEventsR_AINS`
AFTER INSERT ON SystemEventsR
FOR EACH ROW
INSERT INTO SystemEventsRcounter (simpledate, syslogtag, records)
VALUES (NEW.simpledate, NEW.syslogtag, 1)
ON DUPLICATE KEY UPDATE records = records + 1;
In order for it to work you need to create a unique composite index on (simpledate, syslogtag)
CREATE UNIQUE INDEX idx_u_simpledate_syslogtag
ON SystemEventsRcounter (simpledate, syslogtag);
Here is SQLFiddle demo.
If you wanted it your way then it might look like
DELIMITER $$
CREATE TRIGGER `SystemEventsR_AINS`
AFTER INSERT ON SystemEventsR
FOR EACH ROW
BEGIN
IF (
SELECT COUNT(*) simpledate
FROM SystemEventsRcounter
WHERE syslogtag = NEW.syslogtag
AND simpledate = NEW.simpledate
) > 0 THEN
UPDATE SystemEventsRcounter
SET records = records + 1
WHERE SystemEventsRcounter.syslogtag = NEW.syslogtag;
ELSE
INSERT INTO SystemEventsRcounter (simpledate, syslogtag, records)
VALUES (NEW.simpledate, NEW.syslogtag, 1);
END IF;
END$$
DELIMITER ;
Here is SQLFiddle demo.