how to use variable as a column name in trigger - mysql

i try to create some trigger for my web database but there is not working code for my trigger here the problem
BEGIN
DECLARE t INT;
DECLARE b INT;
DECLARE ir INT;
DECLARE tgl INT;
DECLARE kol VARCHAR(3);
SET tgl = "(SELECT RIGHT(booking_checkin, 2) FROM pt_bookings WHERE booking_id = NEW.booking.id)";
SET ir = "(SELECT booked_room_id FROM pt_booked_rooms WHERE booking_id = NEW.booking.id)";
SET b = "(SELECT MID(booking_checkin , 6,2) FROM pt_bookings WHERE booking_id = NEW.booking_id)";
SET t = "SELECT IF((SELECT LEFT(booking_checkin, 4) FROM pt_bookings WHERE booking_id = NEW.booking_id) = 2019 ,'0','1')";
SET kol = "d" + tgl;
UPDATE pt_rooms_availabilities
set kol = kol + (SELECT `booking_nights` FROM `pt_bookings` WHERE booking_id = NEW.booking_id)
WHERE room_id = ir AND y = t AND m= b;
END
the problem is var kol do not read as a column name
maybe anyone can help me ?

It is not possible to do this in a trigger. In general, you could use dynamic sql to use variable column names, see e.g. Dynamic conversion of string into column name. This is however not allowed in stored functions or triggers.
You could use if then else to have a different insert statement for each situation, something like if tgl = 7 then update ... set d7 = d7 + ... elseif tgl = 122 then update ... set d122 = d122 + ....
In most situations though, you can and should avoid this by table design.
I am not sure what you are trying to do exactly, but you could just add a column tglcode to your table, store that value there and then add where tglcode = tgl to your update statement. It looks as if you (or your predecessor) did that or something similar with the variables b and t stored in columns m and t.
If that is a viable solution (or a proper table design) for your problem is hard to say though without more information. But you definitely cannot use the variable kol the way you did in a trigger.

Related

Need Guidance with writing MySQL Trigger

I'll admit, up front, that this is my first MySQL trigger. The MySQL version is 8.0.
I have a table for orders and order line items. In the orders table I have a column that stores the total of all line items. I need a trigger that updates that total every time a line items is added or changed for that order. Here's what I have so far:
CREATE TRIGGER update_line_item_total
AFTER INSERT
ON orderlines.price FOR EACH ROW
BEGIN
-- variable declarations
DECLARE li_order_id INT;
DECLARE li_total DEC;
SET li_order_id = orderlines.order_id;
SET li_total = SUM (orderlines.price) WHERE orderlines.order_id = li_order_id;
-- trigger code
UPDATE orders SET
total_lineitems = li_total
WHERE orders.order_id = li_order_id;
END;
I put this into MySQL Workbench and it was rejected. I know that the DECLARE statements, the 2nd SET statement, and the END statements were the ones flagged as incorrect, however I'm not even sure where to look to find out what's wrong.
Looking for guidance and direction.
Thanks,
Michael Frankel
Wizard Consulting Group, Inc.
your problem is on this line : SET li_total = SUM (orderlines.price) WHERE orderlines.order_id = li_order_id;
add delimiters.
do this :
delimiter |
CREATE TRIGGER update_line_item_total
AFTER INSERT
ON orderlines.price FOR EACH ROW
BEGIN
-- variable declarations
DECLARE li_order_id INT;
DECLARE li_total DEC;
declare li_total_temp dec;
SET li_order_id = orderlines.order_id;
select orderlines.price into li_total_temp WHERE orderlines.order_id = li_order_id;
SET li_total = li_total + li_total_temp;
-- trigger code
UPDATE orders SET
total_lineitems = li_total
WHERE orders.order_id = li_order_id;
END |
delimiter ;

Trigger Loop keeps putting currentStock on 0

So I'm trying to work out a trigger that automatically adds the ingredients from a order (dhh_purchaseorder) to the table dhh_ingredients. It should get the new ordered amount out of dhh_purchaseorderingredient and dump it into the orderAmount variable. Then it should combine the current available stock with the ordered amount in newStock. Then it should update the ingredient table and set the new amounts for the correct ingredients but for some reason it keeps putting the currentStock column in ingredients to 0.
Here is my trigger:
BEGIN
DECLARE orderStatus, orderIngredientName VARCHAR(50);
DECLARE finished INTEGER DEFAULT 0;
DECLARE currentStock, newStock DECIMAL(10,2);
DECLARE orderNo, orderAmount int(10);
DECLARE lookupCursor CURSOR FOR SELECT INGREDIENTingredientName from dhh_purchaseorderingredient WHERE dhh_purchaseorderingredient.PURCHASEpurchaseOrderNo = NEW.purchaseOrderNo;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
SET orderNo = NEW.purchaseOrderNo;
SET orderStatus = NEW.status;
IF(orderStatus = "DELIVERED") THEN
OPEN lookupCursor;
update_loop: LOOP
FETCH lookupCursor INTO orderIngredientName;
IF finished = 1 THEN
LEAVE update_loop;
END IF;
SET orderAmount = (SELECT amount from dhh_purchaseorderingredient WHERE dhh_purchaseorderingredient.PURCHASEpurchaseOrderNo = orderNo AND dhh_purchaseorderingredient.INGREDIENTingredientName = orderIngredientName);
SET currentStock = (SELECT currentStock FROM dhh_ingredient WHERE ingredientName = orderIngredientName);
SET newStock = currentStock + orderAmount;
INSERT INTO temp VALUES(currentStock);
UPDATE dhh_ingredient
SET currentStock = newStock
WHERE ingredientName = ingredientName;
END LOOP update_loop;
CLOSE lookupCursor;
END IF;
END
This is partly an answer and partly a suggestion for a better approach.
One of the many reasons I believe stored procedures are a very bad idea is that they are hard to debug. In this case, it's not easy to figure out what value is being assigned to the various stock amount variables.
A better approach is to use query that does update - without the need for SP variable. It's really easy to test it; just execute and inspect the results. By using such a query in your SP, you eliminate incorrect query logic from your code, allowing you to condense the SP to just the bits that matter - the update.
Fortunately, MySQL provides a way to update through a join, via its multi-table update syntax.
This is what the query could look like:
UPDATE dhh_ingredient, dhh_purchaseorderingredient
SET = currentStock = currentStock - amount
WHERE dhh_purchaseorderingredient.INGREDIENTingredientName = orderIngredientName
AND ingredientName = orderIngredientName
AND dhh_purchaseorderingredient.PURCHASEpurchaseOrderNo = NEW.purchaseOrderNo
AND NEW.status = 'DELIVERED';
No need for local variables or any loops, because the update query does a join and the NEW values are used directly in the query.
So your entire stored procedure becomes simply:
BEGIN
UPDATE dhh_ingredient, dhh_purchaseorderingredient
SET = currentStock = currentStock - amount
WHERE dhh_purchaseorderingredient.INGREDIENTingredientName = orderIngredientName
AND ingredientName = orderIngredientName
AND dhh_purchaseorderingredient.PURCHASEpurchaseOrderNo = NEW.purchaseOrderNo
AND NEW.status = 'DELIVERED';
END
which is easy to understand, maintain and debug - a better solution.

stored procedure syntax in mysql

I am new to writing stored Procedures and I can't seem to find the error in this procedure.
The error is marked near the where part.
I tried looking for an example where the set is done based on a if condition but I can't seem to find such an example. Can anyone point me to my error?
DELIMITER $$
CREATE PROCEDURE `incubation`.`bt_voice_modification`
(in input_slot varchar(45),in input_port varchar(45))
BEGIN
SET #SVLAN_STH:=1000;
SET #SVLAN_DTH:=999;
SET #CVLAN_DTH:=1000;
SET #FLOW_INSTANCE:=1;
UPDATE one_2_one_table
SET L2S_USER_FLOW_INSTANCE = #FLOW_INSTANCE := #FLOW_INSTANCE+1;
SET L2S_NW_SLOT = input_slot;
SET L2S_NW_PORT = input_port;
IF STH_DTH = 'STH' then
set L2S_NW_SVLAN = #SVLAN_STH :=#SVLAN_STH + 1;
ELSE
set L2S_NW_SVLAN = #SVLAN_DTH ;
set L2S_NW_CVLAN = #CVLAN_DTH :=#CVLAN_DTH + 1;
END if;
WHERE IPDSLAM_USER_SLOT = 2 AND L2S_USER_TYPE like "%gplt%";
END
Your code suggest you don't have a very clear picture of how UPDATE statement works or the exact syntax. When you put a ;, it marks the end of the (UPDATE) statement. The syntax is - for one table:
UPDATE tableX
SET columnA = what_value_should_columnA-get ,
columnB = what_value_should_columnB_get ,
...
columnX = what_value_should_columnX_get
WHERE (conditions that restrict the rows that will be affected)
ORDER BY SomeColumn ; --- this can be used in MySQL only. Standard SQL
--- (and most DBMS) do not allow ORDER BY clause in
--- UPDATE statements. Since you are using variables
--- and the order of updating affects the updated values,
--- it's essential that you include an ordering.
So, your UPDATE would be something like:
UPDATE one_2_one_table
SET L2S_USER_FLOW_INSTANCE = #FLOW_INSTANCE := #FLOW_INSTANCE+1 ,
L2S_NW_SLOT = input_slot,
L2S_NW_PORT = input_port,
L2S_NW_SVLAN = CASE WHEN STH_DTH = 'STH'
THEN #SVLAN_STH := #SVLAN_STH + 1
ELSE #SVLAN_DTH
END ,
L2S_NW_CVLAN = CASE WHEN STH_DTH = 'STH'
THEN L2S_NW_CVLAN
ELSE #CVLAN_DTH := #CVLAN_DTH + 1
END
WHERE IPDSLAM_USER_SLOT = 2
AND L2S_USER_TYPE like '%gplt%'
ORDER BY SomeColumn ;

Finding min and max value of the table in a constant time

I have a table which contains relative large data,
so that it takes too long for the statements below:
SELECT MIN(column) FROM table WHERE ...
SELECT MAX(column) FROM table WHERE ...
I tried index the column, but the performance still does not suffice my need.
I also thought of caching min and max value in another table by using trigger or event.
But my MySQL version is 5.0.51a which requires SUPER privilege for trigger and does not support event.
It is IMPOSSIBLE for me to have SUPER privilege or to upgrade MySQL.
(If possible, then no need to ask!)
How to solve this problem just inside MySQL?
That is, without the help of OS.
If your column is indexed, you should find min(column) near instantly, because that is the first value MySQL will find.
Same goes for max(column) on an indexed column.
If you cannot add an index for some reason the following triggers will cache the MIN and MAX value in a separate table.
Note that TRUE = 1 and FALSE = 0.
DELIMITER $$
CREATE TRIGGER ai_table1_each AFTER INSERT ON table1 FOR EACH ROW
BEGIN
UPDATE db_info i
SET i.minimum = LEAST(i.minimum, NEW.col)
,i.maximum = GREATEST(i.maximum, NEW.col)
,i.min_count = (i.min_count * (new.col < i.minumum))
+ (i.minimum = new.col) + (i.minimum < new.col)
,i.max_count = (i.max_count * (new.col > i.maximum))
+ (i.maximum = new.col) + (new.col > i.maximum)
WHERE i.tablename = 'table1';
END $$
CREATE TRIGGER ad_table1_each AFTER DELETE ON table1 FOR EACH ROW
BEGIN
DECLARE new_min_count INTEGER;
DECLARE new_max_count INTEGER;
UPDATE db_info i
SET i.min_count = i.min_count - (i.minimum = old.col)
,i.max_count = i.max_count - (i.maximum = old.col)
WHERE i.tablename = 'table1';
SELECT i.min_count INTO new_min_count, i.max_count INTO new_max_count
FROM db_info i
WHERE i.tablename = 'table1';
IF new_max_count = 0 THEN
UPDATE db_info i
CROSS JOIN (SELECT MAX(col) as new_max FROM table1) m
SET i.max_count = 1
,i.maximum = m.new_max;
END IF;
IF new_min_count = 0 THEN
UPDATE db_info i
CROSS JOIN (SELECT MIN(col) as new_min FROM table1) m
SET i.min_count = 1
,i.minimum = m.new_min;
END IF;
END $$
DELIMITER ;
The after update trigger will be some mix of the insert and delete triggers.

Having issues on a validation for email on a table

What i'm trying to do is to validate the email of a certain register on a trigger. For example if a customer is registered for the first time it should create an email with both first and last name (example: user.last#email.com) however if there's already a register with the same name it should create the email the same way with the first and last name following the customer_id (example: user.last2#email.com).
The code that i have so far is the following:
delimiter $
create trigger before_customer_insert
before insert on customer
for each row
begin
declare emailVal varchar(45);
declare checkData int;
declare checkData2 int;
set checkData = (select count(first_name) from customer where first_name = new.first_name);
set checkData2 = (select count(last_name) from customer where last_name = new.last_name);
if((checkData = 1) and (checkData2 = 1)) then
set new.email = (concat(new.first_name,'.', new.last_name, '#sakilacustomer.org'));
else
set new.email = (concat(new.first_name,'.', new.last_name, new.customer_id, '#sakilacustomer.oeg'));
end if;
if(new.kind_customer is null) then
set new.kind_customer = '1';
end if;
set new.active = 1;
end $
The problem that i'm having is that when it's the first register it inserts the email but with a 0 for example "name.last0#email.com" and if i try and insert with the same information shows the same email. I tried to change the logic in the if statements but still showed the same issues.
Your logic is backward. You have:
if((checkData = 1) and (checkData2 = 1)) then
But you want:
if((checkData = 0) and (checkData2 = 0)) then
You want to use the name without a customer ID when there AREN'T any existing records in the database with those names.
Note I'm not sure your check of looking for first names and last names separately is quite what you want. Wouldn't you want to check if the whole address is found as-is?
The way it's written, if someone named Joe Bloggs tries to join, he'll be joe.bloggs1 if there's anybody else named Joe in the system, even if there is no other Joe Bloggs.