how to use row_count() with transAction? - mysql

i have an stored procedure in mysql like below:
BEGIN
START TRANSACTION;
INSERT INTO tbl1 (v1,v2) VALUES (p1,p2);
UPDATE tbl2 SET s1 = 1 WHERE s2 = s3;
SELECT ROW_COUNT();
COMMIT
END
in this query even the transaction doesn't commit, the row_count will be 1.
in fact my question is that how can i use row_count that it returns 0 if rollback occurred?

I ran into a similar problem recently, but I managed to solve it by selecting the row count inside of the transaction block and then returning it after the commit:
BEGIN
START TRANSACTION;
INSERT INTO tbl1 (v1,v2) VALUES (p1,p2);
UPDATE tbl2 SET s1 = 1 WHERE s2 = s3;
SET #rowCount = (SELECT ROW_COUNT());
COMMIT
SELECT #rowCount;
END
I don't know if this is the best way to solve it, but it seems to work for me :-)

Related

Using IF-THEN-ELSE statement in a mySQL transaction

I am learning MySQL and i have a simple transaction to make. Need to deduct quantity from stock, if there is sufficient stock for a specific item. Else, need to roll back the whole transaction.
I have tried the following code :
SET #item_code = 'PEN-001';
set #balance = (SELECT quantity_in_hand FROM items WHERE item_code = 'PEN-001');
-- ------------------------------------------------
DELIMITER //
START TRANSACTION;
IF (#balance) >= 0 THEN
BEGIN
UPDATE items SET quantity_in_hand = #balance - #purchaseqty WHERE item_code = 'PEN-001'
END;
ELSE
BEGIN
ROLLBACK;
SELECT 'Insufficient Stock';
END;
END IF;
COMMIT;
DELIMITER ;
When I run this query in MySQL, nothing happens, there is no action output or error displayed either. Is this the right approach? And, What is the issue with this code?
You could do:
UPDATE items
SET quantity_in_hand = quantity_in_hand - #purchaseqty
WHERE item_code = 'PEN-001' and quantity_in_hand>=#purchaseqty
and then check ROW_COUNT()
The transaction in your example does nothing as rollback has nothing to do and the update when it happens, is atomic by default.

SQL Rollback not going back to last commit

I'm having problem with the following in SQL:
SELECT
*
FROM
department_dup
ORDER BY dept_no;
Then I ran this piece of code:
COMMIT;
UPDATE department_dup
SET
dept_no = 'd011',
dept_name = 'Quality Control'
;
ROLLBACK;
SELECT * from department_dup;
But the table is not going back to the last commit
Can anyone please tell me what's going wrong here? Thanks!
By default, MySQL starts the session for each new connection with autocommit enabled, so MySQL does a commit after each SQL statement if that statement did not return an error
Option 1: Set autocomit off
SET autocommit = 0
OPtion 2: Use transaction boundaries.
START TRANSACTION;
UPDATE department_dup
SET
dept_no = 'd011',
dept_name = 'Quality Control'
;
ROLLBACK;

how to optimise MySql function to work for concurrent users

I am new to MySQL. Please can you advice on how can i modify below function to ensure it does not throw locking errors when called by multiple users at the same time.
CREATE FUNCTION `get_val`(`P_TABLE` VARCHAR(50)) RETURNS int(11)
DETERMINISTIC
BEGIN
DECLARE pk_value INT DEFAULT 0;
DECLARE pk_found INT DEFAULT 0;
SELECT 1 INTO pk_found FROM pk_keys WHERE TABLE_NAME = P_TABLE;
IF pk_found = 1
THEN
UPDATE pk_keys SET TABLE_VALUE = (TABLE_VALUE + 1 ) WHERE TABLE_NAME = P_TABLE;
ELSE
INSERT INTO pk_keys VALUES ( P_TABLE, 1 );
END IF;
SELECT TABLE_VALUE INTO pk_value FROM pk_keys WHERE TABLE_NAME = P_TABLE;
RETURN pk_value;
END
thanks
CREATE FUNCTION `get_val`(`P_TABLE` VARCHAR(50)) RETURNS int(11)
DETERMINISTIC
MODIFIES SQL DATA
BEGIN
DECLARE pk_value INT DEFAULT 0;
IF EXISTS (SELECT 1 FROM pk_keys WHERE TABLE_NAME = P_TABLE)
THEN
SELECT TABLE_VALUE + 1 INTO pk_value FROM pk_keys WHERE TABLE_NAME = P_TABLE FOR UPDATE;
UPDATE pk_keys SET TABLE_VALUE = pk_value WHERE TABLE_NAME = P_TABLE;
ELSE
SET pk_value = 1;
INSERT INTO pk_keys VALUES ( P_TABLE, pk_value );
END IF;
RETURN pk_value;
END
Have a look at SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE Locking Reads
Let us look at another example: We have an integer counter field in a
table child_codes that we use to assign a unique identifier to each
child added to table child. It is not a good idea to use either
consistent read or a shared mode read to read the present value of the
counter because two users of the database may then see the same value
for the counter, and a duplicate-key error occurs if two users attempt
to add children with the same identifier to the table.
Here, LOCK IN SHARE MODE is not a good solution because if two users
read the counter at the same time, at least one of them ends up in
deadlock when it attempts to update the counter.
To implement reading and incrementing the counter, first perform a
locking read of the counter using FOR UPDATE, and then increment the
counter. For example:
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
A SELECT ... FOR UPDATE reads the latest available data, setting
exclusive locks on each row it reads. Thus, it sets the same locks a
searched SQL UPDATE would set on the rows.
Also I replaced your if condition. EXISTS stops as soon as a row is found.

Trigger conditional

I would like to make a SQL Trigger that will evaluate a query like this:
IF NOT (SELECT * FROM table1 WHERE table1.id=1 AND table1.finished=0)
DO
UPDATE table2 SET finished=1 WHERE table2.id=table1.id
That would tell me that all rows from table1 with an id of 1 are finished (if there are no unfinished(0) rows) and, if so, it should update table2 and set the value finished to 1.
Can anyone help me with the Trigger structure? I'm new when it comes to that.
You can do it this way
DELIMITER //
CREATE TRIGGER tg_au_table1
AFTER UPDATE ON table1
FOR EACH ROW
BEGIN
IF NOT OLD.finished <=> NEW.finished THEN
UPDATE table2 t
SET finished = (EXISTS(SELECT *
FROM table1
WHERE id = t.id
AND finished = 0))
WHERE id = NEW.id;
END IF;
END//
DELIMITER ;
Here is SQLFiddle demo
Extended answer is provided in your other question https://stackoverflow.com/a/21270582/1920232

MYSQL Procedures run, but return 0 rows affected

I call a procedure, it runs, and the console says "0 rows affected". Is this normal behavior for a MySQL procedure ?
The procedures are clearly doing what they should. One procedure has 2 insert statements, another has an insert and update statement, and I've seen the results with my own eyes. There are indeed rows being affected.
I'm not sure that I would use that result later on, but it seems like I'd want to get an accurate response from my DB whether or not anything was updated, especially when its expected.
Thoughts ?
MySQL 5.5 if it matters, and the procedures use transactions over auto-committed statements.
CREATE DEFINER=`root`#`localhost` PROCEDURE `create_issue`(user_id SMALLINT, title varchar(255), body LONGTEXT)
BEGIN
DECLARE MYUSERID SMALLINT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END;
START TRANSACTION;
INSERT INTO tracker.issue (user_id, title, body, creation_date, last_mod_date) values (user_id, title, body, CURDATE(), CURDATE());
UPDATE user_activity SET last_new_issue = CURDATE(), post_count = post_count + 1 WHERE user_activity.user_id = user_id;
COMMIT;
END
Edited to show the actual query. Also I've been searching and as best as I can tell this is a known issue over a year and a half old. So I suppose this one can be closed.
the "0 rows affected" response is for the last statement executed in the stored procedure.
usually i track the number of rows effected by manually counting them into session variables
DELIMITER $$
CREATE PROCEDURE `create_issue`(user_id SMALLINT, title varchar(255), body LONGTEXT)
BEGIN
DECLARE MYUSERID SMALLINT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END;
SET #inserted_rows = 0;
SET #updated_rows = 0;
START TRANSACTION;
INSERT INTO tracker.issue (user_id, title, body, creation_date, last_mod_date) values (user_id, title, body, CURDATE(), CURDATE());
SET #inserted_rows = ROW_COUNT() + #inserted_rows;
UPDATE user_activity SET last_new_issue = CURDATE(), post_count = post_count + 1 WHERE user_activity.user_id = user_id;
SET #updated_rows = ROW_COUNT() + #updated_rows;
COMMIT;
END
$$
the session variables can then be read after the SP was executed.
i am not sure if it is possible to override the response from the ROW_COUNT() function by setting a value to a variable,
I guess this is a reported bug. May be a good question for MySQL mailing list/forum. http://bugs.mysql.com/bug.php?id=44854
Something definitely isn't right. A sproc should still return the number of rows affected if there are multiple inserts occurring. I'm using the same version of MySQL and this works fine for me.
Are you sure you're not doing something like that
...SET col1='value1' AND col2='value2'...
instead of
...SET COL1='value1', col2='value2'...
Could you post your stored procedure?