How to increment using a SQL variable within an update statement - mysql

I am trying to increment a column using an #count variable in SQL. I have tried multiple attempts that I will list below that all result in:
Error Code: 1064
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 ...
First was:
SET #count = 65;
UPDATE table t
SET t.Revision = CHAR(#count)
, #count = #count + 1
WHERE t.hidden = 0;
I am trying to increment every row currently as a proof of concept that this works.
Second was:
DECLARE t CURSOR FOR
SELECT * FROM table
WHERE t.hidden = 0;
OPEN t;
FETCH NEXT FROM t;
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE table t2 SET t2.Revision = 'D' WHERE t2.id1 = t.id1 AND t2.id2 = t.id2;
END;
END
CLOSE t;
DEALLOCATE t;
Once again I am just trying to see if I can set a standard variable using a while loop before I implement incrementing as a proof of concept that it works.
I am not sure why either of these attempts is failing but any help would be appreciated.

Here is how your first example should work(inside of some loop):
first you set your count value, then you update
SET #count = 65;
UPDATE CUSTOMER t
SET t.LName = CONVERT(#count, char)
where t.FName = 'a';
...and then increase that count and you update again...
set #count = #count + 1;
UPDATE CUSTOMER t
SET t.LName = CONVERT(#count, char)
where t.FName = 'a';
But that should be in a procedure for example.
Here is the DEMO. I it a small example and I hope you will find it helpful.
Cheers!

You can try the following solution:
SET #count = 64; -- so the first increment is 65 (starting on A).
UPDATE table_name t
SET t.Revision = CHAR(#count:=#count+1)
WHERE t.hidden = 0;
or (shorter):
UPDATE table_name t, (SELECT #count:=64) t2
SET t.Revision = CHAR(#count:=#count+1)
WHERE t.Hidden = 0;
demo on dbfiddle.uk

Related

MySQL syntax error when using prepared statement with CONCAT

I'm trying to use a prepared statement within a stored procedure. I'm getting the syntax error in the initial SET #idToUpdateQuery. I already know that the CONCAT without the variable assignment using := works correctly, as it's used elsewhere and works as intended. Essentially, I just need to be able to get the result of the prepared SELECT statement into the variable #resultId. The problematic code is as follows:
SET #distinctTableXIds = (SELECT COUNT(*) FROM tempTableX);
SET #i = 0;
WHILE #i < #distinctTableXIds DO
/*CONCAT IS NEEDED HERE TO PASS USER DEFINED #i*/
SET #idToUpdateQuery = CONCAT('SELECT #result := MAX(id)
FROM tableY
WHERE tableZId = (SELECT id FROM tempTableX ORDER BY id LIMIT ', #i, ', 1)');
PREPARE #IdToUpdateStmt FROM #IdToUpdateQuery;
EXECUTE #IdToUpdateStmt;
SET #resultId = SELECT #result;
UPDATE tableY
SET someBoolean = 1
WHERE id = #resultId;
SET #i = #i + 1;
END WHILE;
You don't use the # sigil for a statement name. It's not a user variable.
See example at https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET #a = 3;
mysql> SET #b = 4;
mysql> EXECUTE stmt1 USING #a, #b;
Besides that, I don't think you need a prepared statement for this task at all. I can think of at least two other solutions. Give me a few minutes and I'll write one up.
One solution using a cursor (see https://dev.mysql.com/doc/refman/8.0/en/cursors.html):
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE max_id INT;
DECLARE cur1 CURSOR FOR SELECT MAX(id) FROM tableY JOIN tempTableX ON (tableY.tableZId = temptableX.id) GROUP BY tableZId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO max_id
IF done THEN
LEAVE read_loop;
END IF;
UPDATE tableY SET someBoolean = 1 WHERE id = max_id;
END LOOP;
CLOSE cur2;
END
Another solution that does it all in one UPDATE statement:
UPDATE tableY AS y1
INNER JOIN tempTableX AS x ON (y1.tableZId = x.id)
LEFT OUTER JOIN tableY AS y2 ON (y1.tableZId = y2.tableZId AND y1.id < y2.id)
SET y1.someBoolean = 1
WHERE y2.id IS NULL;
The outer join trick is a way to find the row of y1 for which no row exists with the same tableZId and a greater id. In other words, it finds the largest id for each group of rows with a given tableZId.

Select count(*) and select sum(my_data) after insert- error syntax#1064

I am a beginner in sql, and even in programming, recently I discovered the triggers, and I want to calculate the maximum number of active lines, and the total sum of active weights
ps: active records are defined with 'cancled = 0'
I had error # 1064 near the line where I declared my variable (row 2)
i am running this into PHPMYADMIN (MySQL) triggers.
BEGIN
DECLARE #max_rows int;
DECLARE #max_tare int;
SET #max_rows = SELECT COUNT(*) FROM history WHERE cancled = 0;
SET #max_tare= SELECT SUM(tare) FROM history WHERE cancled = 0;
UPDATE max_tare
SET max_row = #max_rows,
max_tare = #max_tare
WHERE id = 1
END
I was expecting that I updated line 1 with the max number of rows and the total sum of active weights but I have an error
MySQL replied: # 1064 - Syntax error near '#max_rows int; DECLARE
#max_tare int; SET #max_rows = SELECT COUNT (*) FROM his' at line 2
after Paul comment i changed the code to this :
BEGIN
DECLARE max_r int;
DECLARE max_t int;
SET max_r = SELECT COUNT(*) FROM history WHERE cancled = 0;
SET max_t = SELECT SUM(tare) FROM history WHERE cancled = 0;
UPDATE max_tare
SET max_row = max_r,
max_tare = max_t
WHERE id = 1
END
this is the new error :
MySQL replied: # 1064 - Syntax error near SELECT COUNT (*) FROM
history WHERE cancled = 0; SET max_t = SELECT SUM (tare) FR 'at line 4
ty in advance.
thanks to #paul Spiegel and #forpas for helping
this code helped solved the problem
IF(NEW.mix != '') THEN
UPDATE max_tare
SET max_row = (SELECT COUNT(*) FROM history WHERE nom LIKE NEW.mix),
max_tare = (SELECT SUM(tare) FROM history WHERE cancled = 0)
WHERE id = 1;
ELSE
UPDATE max_tare
SET max_row = (SELECT COUNT(*) FROM history WHERE cancled = 0),
max_tare = (SELECT SUM(tare) FROM history WHERE cancled = 0)
WHERE id = 1;
END IF;
END
this worked fine for me, thanks guys

Loop in a MySql stored procedure error code 1064

I'm reasonably new to writing MySQL stored procedures, and I'm trying to get my head around using loops and variables.
I have a table with a column called STAT_NAME, where several rows could have the same value for that column. I want to create a temporary column which numbers the occurrences of each STAT_NAME value, so for example first time STAT_NAME is "stat A", set STAT_COUNT to 1, 2nd time 2 etc. And then start again at 1 for "stat B" and so on.
I've got as far as creating the the temporary table with an empty column called STAT_COUNT, and sorted the table by STAT_NAME.
I've then tried to loop through all the rows and set STAT_COUNT accordingly. However, I get the following error:
Error Code: 1064. 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 '#counting,1) THEN SET #STAT_NAME_CURR = (SELECT #STAT_NAME FROM tmp1 LIMIT #'
Is anyone able to explain why what I've written is not OK? I think it would be fine if I used a system variable instead of #counting, and I don't understand why. I've tried googling the problem but not getting anywhere!
cheers.
DROP PROCEDURE IF EXISTS collate_stats;
delimiter //
CREATE PROCEDURE collate_stats()
begin
create temporary table tmp1 engine=memory
SELECT STAT_NAME, STAT, '' AS STAT_COUNT
FROM performance_testing_stats.20131014
ORDER BY STAT_NAME;
-- stat name that we are currently looking at
SET #STAT_NAME_CURR := "";
-- number of times this name has been found so far
SET #STAT_NAME_COUNT := 0;
-- Use to loop through all rows
SET #n := (SELECT COUNT(*) FROM tmp1);
-- Row reached so far
SET #counting := 0;
WHILE #counting < #n DO
-- IF #STAT_NAME_CURR is not equal to the STAT_NAME for the current row,
-- THEN set #STAT_NAME_CURR to STAT_NAME value and reset #STAT_NAME_COUNT
-- ELSE just increment #STAT_NAME_COUNT
IF #STAT_NAME_CURR <> (SELECT #STAT_NAME FROM tmp1 LIMIT #counting,1) THEN
SET #STAT_NAME_CURR = (SELECT #STAT_NAME FROM tmp1 LIMIT #counting,1);
SET #STAT_NAME_COUNT = 0;
ELSE
SET #STAT_NAME_COUNT = #STAT_NAME_COUNT + 1;
END IF;
-- Set STAT_COUNT for current row to value of #STAT_NAME_COUNT
UPDATE tmp1 SET STAT_COUNT = #STAT_NAME_COUNT WHERE STAT_NAME = #STAT_NAME_CURR AND STAT_COUNT = '' LIMIT 1;
-- Move to next row
SET #counting = #counting + 1;
END WHILE;
select * from tmp1;
END //
delimiter ;
You might want to look into using cursors instead of the while loop.
However, you could probably accomplish what you are trying to do with a simple GROUP BY query:
SELECT STAT_NAME, STAT, COUNT(1) as STAT_COUNT
FROM performance_testing_stats.20131014
GROUP BY STAT_NAME, STAT
ORDER BY STAT_NAME, STAT;
Unless I'm missing something about what you are doing.

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.