Error: [sql] Couldn't insert SQL accounting START record - Can't update table 'useraccounting' in stored function/trigger because it is already used by statement which invoked this stored function/trigger
We get the above error frequently after the user authenticated and it take more than 1 min for the user to appear in online table. Any idea about the cause and solutions?
Thanks
Update:
Below the trigger that is used:
CREATE DEFINER=`mysql`#`%` TRIGGER `radacct_after_update` AFTER UPDATE ON `radacct` FOR EACH ROW BEGIN
if (NEW.acctoutputoctets != OLD.acctoutputoctets)
THEN
UPDATE useraccounting SET tmpQuta = tmpQuta + (New.acctoutputoctets - OLD.acctoutputoctets)
WHERE EXISTS (SELECT * FROM users WHERE users.userable_id = useraccounting.client_id AND users.userable_type = 'App\\Models\\Client' AND (users.username = New.username));
END IF;
END
UPDATE2: we have created 2 triggers. One on INSERT and another one on UPDATE.
After INSERT on radacct:
BEGIN
UPDATE useraccounting SET tmpQuta = New.acctoutputoctets
WHERE EXISTS (SELECT * FROM users WHERE users.userable_id = useraccounting.client_id AND users.userable_type = 'App\\Models\\Client' AND (users.username = New.username));
END
after UPDATE on radacct:
BEGIN
if (NEW.acctoutputoctets != OLD.acctoutputoctets)
THEN
UPDATE useraccounting SET tmpQuta = tmpQuta + (New.acctoutputoctets - OLD.acctoutputoctets)
WHERE EXISTS (SELECT * FROM users WHERE users.userable_id = useraccounting.client_id AND users.userable_type = 'App\\Models\\Client' AND (users.username = New.username));
END IF;
END
Related
I'm creating a MySQL trigger designed to update various tables with a new value if certain values are changed by an UPDATE query. I keep receiving the following syntax error for this particular trigger:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 29
Line 29 in this case is the line of the END statement.
This is my full code:
DELIMITER $$
CREATE TRIGGER update_selling_prices BEFORE UPDATE ON t1
FOR EACH ROW
BEGIN
DECLARE update_price INT DEFAULT 0;
DECLARE selling_price_1 DECIMAL(10, 3) DEFAULT 0.000;
DECLARE selling_price_2 DECIMAL(10, 3) DEFAULT 0.000;
IF (OLD.rrp_price <> NEW.rrp_price OR OLD.discount_1 <> NEW.discount_1 OR OLD.discount_2 <> NEW.discount_2 OR OLD.net_price <> NEW.net_price OR OLD.markup <> NEW.markup OR OLD.delivery_cost <> NEW.delivery_cost) THEN
SET update_price = (SELECT b.is_auto_update FROM price_categories c INNER JOIN brands b ON b.brand_name = c.brand_name WHERE c.id = NEW.category_id LIMIT 1);
IF (update_price = 1) THEN
IF (NEW.is_bundle = 0) THEN
UPDATE t2 SET temp = 'Fired Single' WHERE id = NEW.id;
ELSE IF (NEW.is_bundle = 1) THEN
UPDATE t2 SET temp = 'Fired Bundle' WHERE id = NEW.id;
END IF;
END IF;
END IF;
END;
$$
DELIMITER ;
The current UPDATE statements are just placeholders for some actual calculations I'll end up doing.
Please note: I use Sequel Pro for most MySQL-related stuff and initially was using their GUI to try and add the trigger - it automatically adds the surrounding code so I would only create everything between the BEGIN and END statements. That also resulted in this same syntax error, so I don't believe it's related to the delimiters like some similar threads I've already found on here. Nevertheless, I've tried adding the full trigger code via a normal query; changing the delimiter syntax - for example END$$, END $$, END; $$ etc.
I've successfully created other triggers with similar syntax, but they do not include the DECLARE syntax.
Where am I going wrong?
The problem is here:
IF (NEW.is_bundle = 0) THEN
UPDATE t2 SET temp = 'Fired Single' WHERE id = NEW.id;
ELSE IF (NEW.is_bundle = 1) THEN
UPDATE t2 SET temp = 'Fired Bundle' WHERE id = NEW.id;
END IF;
Review documentation: https://dev.mysql.com/doc/refman/8.0/en/if.html
MySQL supports ELSEIF and this is different than ELSE IF. If you use ELSEIF, this continues the structure of the IF statement. If you use ELSE IF, it starts a new IF statement, so it should be like this:
IF (NEW.is_bundle = 0) THEN
UPDATE t2 SET temp = 'Fired Single' WHERE id = NEW.id;
ELSE
IF (NEW.is_bundle = 1) THEN
UPDATE t2 SET temp = 'Fired Bundle' WHERE id = NEW.id;
END IF;
END IF;
See that there is a complete IF/THEN/END IF statement within the ELSE block of the outer one?
But you didn't do that, so the END IF applies to the innermost IF statement, and then you're one level off for the rest of the body of the trigger.
When MySQL gets to the end of the whole CREATE TRIGGER statement, if there aren't enough ENDs to balance the blocks you began, MySQL complains with the error you saw.
I am trying to update an entry if already exists using a trigger. I would like to check if an entry exists update if not then insert. When I tried to insert new entry I got an error: 'Can't update table in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
DELIMITER //
CREATE TRIGGER check_table_before_insert BEFORE INSERT ON Songs FOR EACH ROW BEGIN IF NEW.PageURL =(
SELECT
Songs.PageURL
FROM
Songs
WHERE
Songs.PageURL = NEW.PageURL
) THEN
UPDATE
Songs
SET
Songs.Title = NEW.Title,
Songs.Album = NEW.Album,
Songs.Label = NEW.Label,
Songs.Release_Date = NEW.Release_Date,
Songs.PageURL = NEW.PageURL,
Songs.IsSingle = NEW.IsSingle,
Songs.Code = NEW.Code,
Songs.ImageURL = NEW.ImageURL,
Songs.Link_320 = NEW.Link_320,
Songs.Link_128 = NEW.Link_128,
Songs.Link_48 = NEW.Link_48,
Songs.AlbumURL = NEW.AlbumURL
WHERE
Songs.PageURL = NEW.PageURL;
END IF;
END;
// DELIMITER;
This isn't an appropriate use for a trigger.
If you want to perform a "insert or update" operation on a table, use the INSERT … ON DUPLICATE KEY UPDATE … syntax. It already has the semantics you are looking for.
If the columns you are updating amount to the entirety of the row, you may be able to use the REPLACE verb as an alternative to INSERT. Note that it will delete the row before insetting a new one, so any columns not included in the REPLACE query will be lost.
I have two tables in mysql db, one is account master table and the another one is account transaction table. On insert/update/delete on the transaction table I have to update the available balance and the last transaction date in the account master table ( the account master table contains more than 1 account). Is it possible with a trigger?
I have tried with the following Trigger. But trigger is not getting executed, getting syntax error(MSG 1064 LINE 30 MY SQL DB ERROR).
Please help to resolve if this can be handled through a trigger.
DELIMITER $$
CREATE TRIGGER wlt_bal_upd_insert AFTER INSERT ON wallet_txns
FOR EACH ROW
BEGIN
UPDATE wallet_accounts
SET wlt_bal_available = select sum(IF(wlt_txn_type = 'Expense', -wlt_txn_amount, wlt_txn_amount))from wallet_txns where wlt_name = new.wlt_name,wlt_last_txn_date = select MAX(wlt_txn_date)from wallet_txns where wlt_name = NEW.wlt_name
WHERE wlt_holder_id = NEW.wlt_holder_id
and wlt_name = new.wlt_name;
END $$
DELIMITER ;
I just forgot to put the brackets (). Its working now. Here is the modified code.
DELIMITER $$
CREATE TRIGGER wlt_bal_upd_insert AFTER INSERT ON wallet_txns
FOR EACH ROW
BEGIN
UPDATE wallet_accounts
SET wlt_bal_available = (select sum(IF(wlt_txn_type = 'Expense', -wlt_txn_amount, wlt_txn_amount))from wallet_txns where wlt_name = new.wlt_name),wlt_last_txn_date = (select MAX(wlt_txn_date)from wallet_txns where wlt_name = NEW.wlt_name)
WHERE wlt_holder_id = NEW.wlt_holder_id
and wlt_name = new.wlt_name;
END $$
DELIMITER ;
I am trying to run the following script in mysql :
DELIMITER $$$
DROP TRIGGER IF EXISTS invoice_line_insert
$$$
CREATE TRIGGER invoice_line_insert AFTER INSERT
ON invoice_line FOR EACH ROW
BEGIN
IF NEW.type = "DELIVERY" THEN
UPDATE invoice
SET invoice.etdelivery_amount = invoice.etdelivery_amount + NEW.amount
WHERE invoice.id_invoice = NEW.invoice_parent_id_invoice;
ELSE
UPDATE invoice
SET invoice.etexpense_amount = invoice.etexpense_amount + NEW.amount
WHERE invoice.id_invoice = NEW.invoice_parent_id_invoice;
END IF;
UPDATE invoice
SET invoice.vatamount = (NEW.amount * ((
SELECT vat.rate
FROM vat
WHERE vat.id_vat = NEW.vat_id_vat
) / 100)) + invoice.vatamount
WHERE invoice.id_invoice = NEW.invoice_parent_id_invoice;
UPDATE invoice
SET invoice.itamount = invoice.vatamount +
invoice.etdelivery_amount +
invoice.etexpense_amount
WHERE invoice.id_invoice = NEW.invoice_parent_id_invoice;
END
$$$
When I run it in mySql Workbench, it is working fine, but when play 2 run it authomatically (in a file called 2.sql) I get the following error :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER $$$ DROP TRIGGER IF EXISTS invoice_line_insert $$$ CREATE TRIGGER invo' at line 1 [ERROR:1064, SQLSTATE:42000], while trying to run this SQL script:
I read on the internet that the delimiter statement is only working on specific gui, not every time. Is that true ? Why ? How to resolve it because I need the delimiter statement ?
Thanks for your help.
This seems to be a duplicate of Play framework 2.0 evolutions and create trigger
(Note that, in my view, the better answer is the one posted by Roger on May 24 2013, i.e. the link above)
"delimiter" cannot be used in the evolution script text; I can't seem to find any documentation as to why this is so. But maybe it is got to do with the fact that "delimiter" is not an SQL statement but an SQL property.
However, there is a solution in the Evolutions section of Play 2 docs:
Play splits your .sql files into a series of semicolon-delimited statements before executing them one-by-one against the database. So if you need to use a semicolon within a statement, escape it by entering ;; instead of ;. For example, INSERT INTO punctuation(name, character) VALUES ('semicolon', ';;');.
So in your case,
Remove the "delimiter" property, and
Use ";;" instead of ";" for your inner SQL statements, so as to prevent the Play 2 parser from executing these inner SQL statements separately.
Here is an example that I have successfully tested in Play 2.3 and mysql 14.14 Distrib 5.5.40 (Ubuntu 12.04LTS):
DROP TRIGGER IF EXISTS SOFTWARE_INSERT_CT_TRIGGER;
CREATE TRIGGER SOFTWARE_INSERT_CT_TRIGGER
BEFORE INSERT ON SOFTWARE
FOR EACH ROW
BEGIN
IF NEW.CREATED_TIME = '0000-00-00 00:00:00' THEN
SET NEW.CREATED_TIME = NOW();;
END IF;;
END;
In the case of your SQL script, the following should work with Play 2.1 and above (Note that I have not tested it):
DROP TRIGGER IF EXISTS invoice_line_insert;
CREATE TRIGGER invoice_line_insert AFTER INSERT
ON invoice_line FOR EACH ROW
BEGIN
IF NEW.type = "DELIVERY" THEN
UPDATE invoice
SET invoice.etdelivery_amount = invoice.etdelivery_amount + NEW.amount
WHERE invoice.id_invoice = NEW.invoice_parent_id_invoice;;
ELSE
UPDATE invoice
SET invoice.etexpense_amount = invoice.etexpense_amount + NEW.amount
WHERE invoice.id_invoice = NEW.invoice_parent_id_invoice;;
END IF;;
UPDATE invoice
SET invoice.vatamount = (NEW.amount * ((
SELECT vat.rate
FROM vat
WHERE vat.id_vat = NEW.vat_id_vat
) / 100)) + invoice.vatamount
WHERE invoice.id_invoice = NEW.invoice_parent_id_invoice;;
UPDATE invoice
SET invoice.itamount = invoice.vatamount +
invoice.etdelivery_amount +
invoice.etexpense_amount
WHERE invoice.id_invoice = NEW.invoice_parent_id_invoice;;
END;
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.