MySQL stored procedure UPDATE changing first row only - mysql

I have the following watching table
If I run this simple test query:
UPDATE
`watching`
SET
`lastPriceSeen` = 1.33
WHERE
`email` = 'blablanfff#gmail.com' AND
`productId` = 254857265
LIMIT 1
row ID 10 correctly updates to 1.33 in the lastPriceSeen column
If I convert this to a stored procedure:
DELIMITER ;;
CREATE PROCEDURE `updateLastSeenPrice`(
email VARCHAR(100),
productId INT(11),
price FLOAT
)
DETERMINISTIC
COMMENT 'Updates watcher last seen price'
BEGIN
UPDATE
`watching`
SET
`lastPriceSeen` = price
WHERE
`email` = email AND
`productId` = productId
LIMIT 1;
END;;
DELIMITER ;
and run CALL updateLastSeenPrice('blablanfff#gmail.com','254857265', 1.11)
Only the first row (ID 1) gets updated with the price, when I was expecting row ID 10 to update.
This makes no sense to me, the WHERE clause should prevent this from happening, and it's the same query! I've even added a SELECT at the end of the stored procedure to test it's receiving the IN parameters correctly and it is...
Any ideas as to why the first row gets updated? Why is it matching on that when the WHERE clause should prevent it from doing so?

The WHERE clause doesn't see the difference between the column name and parameter name. Therefore, any record will do and it will update the first one.
Change it into:
CREATE PROCEDURE `updateLastSeenPrice`(
p_email VARCHAR(100),
p_productId INT(11),
p_price FLOAT
)
DETERMINISTIC
COMMENT 'Updates watcher last seen price'
BEGIN
UPDATE
`watching`
SET
`lastPriceSeen` = p_price
WHERE
`email` = p_email AND
`productId` = p_productId
LIMIT 1;
END;;
DELIMITER ;

Related

Unable to diagnose the problem with MySQL stored procedure

I have defined the following stored procedure to add/update a table called ImportedProduct.
If the primary key, ImportedProductId is provided and is greater than zero, then update the exiting record otherwise insert a new one:
DELIMITER //
CREATE PROCEDURE AddOrUpdateImportedProduct (
IN ImportedProductId BIGINT,
IN UniqueThirdPartyCode VARCHAR(64),
IN BranchId BIGINT
)
BEGIN
IF ImportedProductId <= 0 THEN
INSERT INTO ImportedProduct(UniqueThirdPartyCode, BranchId)
VALUES(UniqueThirdPartyCode, BranchId);
ELSE
UPDATE
ImportedProduct
SET
UniqueThirdPartyCode = UniqueThirdPartyCode,
BranchId = BranchId
WHERE
ImportedProductId = ImportedProductId;
END IF;
END //
DELIMITER ;
Now I run the following code to update an existing row:
CALL AddOrUpdateImportedProduct (1, 'y-105', 24);
I can see that the record with with ImportedProductId = 1 exists in the table, but I am getting the following error:
You are using safe update mode and you tried to update a table without
a WHERE that uses a KEY column To disable safe mode
I am pretty sure ImportedProductId = ImportedProductId holds always.. Perhaps rename your variable or add an alias to the updated table.

MySQL Case Error 1111 - Max(Column) Case Statement in SP

Summary: I am trying to add a Username to the db.username_table with a unique ID incremented by 1. However, I keep receiving an error 1111 related to my CASE statement. It should make the first User_ID 1, then all other new ones the max(user_id) +1. Any help would be greatly appreciated!
Background: This is for my first MySQL project - I have some experience with MS SQL that may be hindering me here. I googled many references and streamlined my code as much as possible, but the aggregate for the counter returns a 1111 error with an IF or with a CASE statement.
DELIMITER $$
CREATE PROCEDURE db.add_user
(
in new_username varchar(45)
)
begin
-- Set Counter ID
declare new_user_id int;
set new_user_id = if(max(db.username_table.User_ID) is null, 1, max(db.username_table.User_ID) + 1);
-- Add Username with Counter
insert into db.username_table (user_id, username)
values (new_user_id, new_username);
END$$
DELIMITER ;
Expected Result - Add a Username to the db.username_table with a unique ID incremented by 1.
Actual Result - Error 1111.
You are using the funtion MAX but not in SQL statements .. so the max of is used improperly . you need a select for retrive a MAX(db.username_table.User_ID.)
declare new_user_id int;
select case when
max(ifnull(db.username_table.User_ID,0)) = 0
then 1
else max(db.username_table.User_ID) + 1 end
INTO new_user_id
from your_table ;
but could you simply need an autoincrement column for User_id and avoid this SP
CREATE TABLE your_table (
User_ID int(11) NOT NULL AUTO_INCREMENT,
....
)

How to trigger update child records on parent update in the same table

I have a user table that has both child and parent user accounts in it.
Child accounts are indicated by a parent id field
I have created a stored procedure that takes all the necessary info and can update the user's fields successfully when manually run and given a specific ID to update
Then I have a trigger that can successfully get the child users it needs to update.
The problem, however, is when I try and make the trigger call the procedure I get the error
"Can't update table 'userinfos' in stored function/trigger because it is already used by statement which invoked this stored function/trigger"
Below is my code in which I check before running the stored procedure that the update it triggered on was done on a parent and not a child. This means if it triggered on a child update then it won't run the stored procedure and therefore can't ever get stuck in a loop. (Note both BEFORE and AFTER don't work)
CREATE TRIGGER `update_child_users` BEFORE UPDATE ON `abcd_virtuemart_userinfos`
FOR EACH ROW BEGIN
IF OLD.`primary_user_id` = NEW.`primary_user_id` AND (NEW.`primary_user_id` = 0 OR NEW.`primary_user_id` = '' OR NEW.`primary_user_id` IS NULL)
THEN
CALL sys.`update_child_user`(NEW.`company`, NEW.`last_name`, NEW.`first_name`, NEW.`middle_name`, NEW.`phone_1`, NEW.`phone_2`, NEW.`fax`, NEW.`address_1`, NEW.`address_2`, NEW.`city`, NEW.`virtuemart_state_id`, NEW.`virtuemart_country_id`, NEW.`zip`, NEW.`billing_email_address`, NEW.`virtuemart_user_id`);
END IF;
END
And the stored procedure
DELIMITER $$
CREATE DEFINER=`~DEFINER HERE~`
PROCEDURE `update_child_user`(IN `n_company` VARCHAR(64), IN `n_last_name` VARCHAR(48), IN `n_first_name` VARCHAR(48), IN `n_middle_name` VARCHAR(48), IN `n_phone_1` VARCHAR(32), IN `n_phone_2` VARCHAR(32), IN `n_fax` VARCHAR(32), IN `n_address_1` VARCHAR(64), IN `n_address_2` VARCHAR(64), IN `n_city` VARCHAR(64), IN `n_virtuemart_state_id` SMALLINT(1), IN `n_virtuemart_country_id` VARCHAR(255), IN `n_zip` VARCHAR(32), IN `n_billing_email_address` VARCHAR(255), IN `n_virtuemart_user_id` INT(1))
MODIFIES SQL DATA
UPDATE `userinfos`
SET `company` = `n_company` ,
`last_name` = `n_last_name` ,
`first_name` = `n_first_name` ,
`middle_name` = `n_middle_name` ,
`phone_1` = `n_phone_1` ,
`phone_2` = `n_phone_2` ,
`fax` = `n_fax` ,
`address_1` = `n_address_1` ,
`address_2` = `n_address_2` ,
`city` = `n_city` ,
`virtuemart_state_id` = `n_virtuemart_state_id` ,
`virtuemart_country_id` = `n_virtuemart_country_id` ,
`zip` = `n_zip` ,
`billing_email_address` = `n_billing_email_address`
WHERE `primary_user_id` = `n_virtuemart_user_id`
$$ delimiter ;
So how can I go about either just letting this trigger be able to run recursively as there are others I don't or can I change my syntax in some way that doesn't set off the recursive blocking trigger?

Mysql Stored Proc not returning a VARCHAR out parameter

Below is my stored procedure. It works fine but my problem is I can't get the output parameter as VARCHAR.
The part where I'm having problem is the assignment of #curcName to the out parameter op_resultMessage
BEGIN
SET op_resultMessage = #curcName;
END;
Here's the Stored Procedure.
CREATE DEFINER=`root`#`localhost` PROCEDURE `addCurriculum`(
IN p_curcName varchar(100),
IN p_description TEXT,
IN p_yearLevel VARCHAR(50),
IN p_syStart INT,
IN p_syEnd INT,
IN p_creator VARCHAR(50),
OUT op_resultMessage VARCHAR(50))
BEGIN
DECLARE curcName VARCHAR(20) ;
IF EXISTS
(SELECT #curcName := `name`
FROM curriculum
WHERE
yearLevel = p_yearLevel
AND syStart = p_syStart
AND syEnd = p_syEnd )
THEN --
BEGIN
SET op_resultMessage = #curcName;
END;
ELSE
BEGIN
INSERT INTO curriculum(`name`, description, yearLevel, syStart, syEnd, creator)
VALUES(p_curcName,p_description,p_yearLevel,p_syStart,p_syEnd,p_creator);
END;
END IF;
END
I'm trying to return a message IF name EXISTS
So it should go something like
SET op_resultMessage = #curcName 'already uses the school year and year level you're trying to insert';
But I don't know how to properly concatenate and assign values. I'm still confused with := SET and = operators. I guess that's where I'm having problems with.
If I change the out parameter's type to an INT like
OUT op_resultMessage VARCHAR(50)
then assigns a number to op_resultMessage like SET op_resultMessage = 1;
It returns the number 1 as out parameter values. It just won't work with varchar.
So when I try to call the procedure
CALL `enrollmentdb`.`addCurriculum`
('Test Curriculum ','Test ','Grade 1',2015,2016,'jordan',#outputMsg);
SELECT #outputMsg; -- this doesn't return any value even if Grade 1, 2015 and 2016 exists
I'd appreciate any help. I actually just learned mysql recently.
Thanks.
drop procedure if exists addCurriculum;
delimiter $$
CREATE PROCEDURE `addCurriculum`(
IN p_curcName varchar(100),
IN p_description TEXT,
IN p_yearLevel VARCHAR(50),
IN p_syStart INT,
IN p_syEnd INT,
IN p_creator VARCHAR(50),
OUT op_resultMessage VARCHAR(50))
BEGIN
DECLARE curcName VARCHAR(20) ;
SELECT `name` into #curcName
FROM curriculum
WHERE
yearLevel = p_yearLevel
AND syStart = p_syStart
AND syEnd = p_syEnd
LIMIT 1;
-- Note change above. When selecting into a variable (or more than 1)
-- then 0 or 1 rows can come back max or an Error occurs
IF #curcName is not null then
SET op_resultMessage = #curcName;
ELSE
BEGIN
INSERT INTO curriculum(`name`, description, yearLevel, syStart, syEnd, creator)
VALUES(p_curcName,p_description,p_yearLevel,p_syStart,p_syEnd,p_creator);
END;
SET op_resultMessage = 'GEEZ I am right here'; -- Drew added this
END IF;
END$$
delimiter ;
Note the commentary in the stored procedure, especially the part of only 0 or 1 rows returning else an Error will occur with a select into var pattern. So LIMIT 1. That may or may not be the row you want (limit 1), but that is where it is at right now.

MySQL - Update a column after information get's inserted

I have a table in MySql table like the following
row_timestamp timestamp
, row_id int(11) auto_increment
, mrn char(17)
, patients_last_name varchar(50)
, patients_first_name varchar(50)
, ssn char(4) default '0000'
, visit_key NULL
upon the insertion of a record, I'd like visit_key to bet set to visit_key = concat(mrn, row_id) I was trying to accomplish this with a before insert trigger to no avail, I kept getting that the mrn column was not in the field select list.
Update
I tried the following, which seems not to work because the auto_increment has not yet incremented:
set new.visit_key = concat(new.mrn, new.row_id)
I also tried
set new.visit_key = concat(new.mrn, max(row_id)+1)
I am thinking of the trigger to sort of act like a calculated field in MS Access, is this reasonable? Thoughts? Would it not be possible to do since the visit_key would technically be NULL and you cannot update a new value?
UPDATE
I used the following code that I adapted from this question here
DELIMITER //
CREATE TRIGGER vkt AFTER INSERT ON demographic_information
FOR EACH ROW
BEGIN
UPDATE `demographic_information` SET visit_key_test = concat(new.mrn, mew.row_id) WHERE row_id = NEW.row_id;
END;
//
DELIMITER ;
and got the following error message:
INSERT INTO `manchuco_nys_trauma`.`demographic_information` (
`row_timestamp` ,
`row_id` ,
`mrn` ,
`patients_last_name` ,
`patients_first_name` ,
`ssn` ,
`visit_id` ,
`visit_key_test`
)
VALUES (
CURRENT_TIMESTAMP , NULL , '123456', 'Sanderson', 'Steven', '1234', '12345670', NULL
)
MySQL said: Documentation
#1442 - Can't update table 'demographic_information' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Thank you,
What you observe seems normal: since you're using BEFORE INSERT the id value doen't exist yet.
And the same applies for your try with concat(new.mrn, **new**.row_id): NEW has no sense at the moment.
So I suggest you use AFTER INSERT instead.
Try selecting the auto increment value inside the trigger:
CREATE TRIGGER trigger_name AFTER INSERT ON yourTable FOR EACH ROW
BEGIN
DECLARE next_id integer;
SET next_id = (SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA='yourDB' AND TABLE_NAME='yourTable');
SET new.visit_key = CONCAT(new.mrn, next_id);
END
I discovered this approach in this SO article.