In my testing environment, I created the following procedure:-
CREATE DEFINER=`SC1`#`%` PROCEDURE `sc1_procedure_wipe_perms`(IN UserUUID char(36))
BEGIN
DELETE FROM subAccountPermissions WHERE `UserUUID` = UserUUID;
END
Innocent enough, right?
I call it from Java as follows:-
connection = ConnectionMgr.getConnectionToSc1();
rmStatement = connection.prepareStatement("CALL sc1_procedure_wipe_perms(?)");
rmStatement.setString(1, UserUUID);
rmStatement.execute();
It deletes everything. I am unsure what is going on here?
The problem is in the ambiguity between the procedure parameter UserUUID and the table column UserUUID. The MySQL compiler will ignore the parameter and take the table column for both sides of the condition, which means it will resolve to true for all rows.
You need to disambiguate the names, and use a different name for the procedure parameter, for example UserUUIDToDelete.
Related
I'm facing a problem very similar to this issue:
MySQL stored procedure only returns last row of data
Let me explain the scenario first.
I'm using phplist and I have created a custom attribute acting as "per user token"; it is used to create a custom unsubscribe links.
Sometimes I'm in the need to get such token manually knowing the user email address.
So, here is the two involved tables are (note: only relevand fields here):
phplist_user_user: id,email
phplist_user_user_attribute: attributeid,userid,value
With dbeaver ide, executing the following query I correctly get the user token:
SELECT value AS token FROM phplist_user_user_attribute WHERE attributeid=3 and userid=(SELECT MAX(`id`) FROM phplist_user_user WHERE `email`='useremail#domain.ext');
If I put this query inside a stored procedure instead it always returns the very last token inserted to the table, regardless the correctness of email:
CREATE DEFINER=`root`#`%` PROCEDURE `phplist`.`GetTokenFromEmail`(IN `email` VARCHAR(255))
BEGIN
SELECT value AS token
FROM phplist_user_user_attribute
WHERE attributeid=3
and userid=(SELECT MAX(`id`)
FROM phplist_user_user
WHERE `email`=email);
END
Checking at phplist_user_user_attribute table it equals to the very last row:
This is a standard/default phplist installation, so I'm probably doing something wrong with the procedure I don't really understand what.
Thank you for any help!
WHERE `email`=email
Both columns are taken from phplist_user_user table - so the condition value is always TRUE until phplist_user_user.email is NULL.
Remember - if query's rowsource contains more than one table (including a case of copies of the same table) then specify table name/alias for EACH column name.
Situation: Having a SQL procedure which "returns" result via "SELECT x" statements. For some reasons it is not allowed to change it to a function or changing that procedure in any way. How can I obtain the result like:
set #result = 0;
#result = call SomeProcedure(#p1, #p2);
But since it is a procedure not a function above code won't compile/work. How can I achieve that in MySQL. In C++ it works but in MySQL I found no way ...
It is not possible.
Result sets returned from select ... will always be returned to the caller of the first procedure, even if you make several levels of sub calls.
Functions return a value (but not a result set) that you can use inside other procedures or functions.
Your only option is to either set session variables or to store the result in a temporary table that the calling procedure knows about.
[SQL Server 2008 Std]
I have a stored procedure that is used to insert new data into a table, which works as expected. However I now need to call this stored procedure multiple times using the results of a query as the parameters.
e.g.
select
name, age, foo, bar
from
sometable
where
wobble = 'true'
exec insertProc name age foo bar
I know I can use a cursor to acheive this, but I keep reading that "cursors are bad"...but I don't know any other way to do this?
One solution is to use cursor. Other is to prepare your result set into temp table before calling the procedure and then supply it to the procedure ( you have to alter the procedure by adding table-value param as input param). Some info in msdn.
After Googling for awhile I didn't see an answer. Anyway I have a situation in a stored procedure where I do a set select like:
SET someVariable = (SELECT ...)
Anyway, due to some redundant records existing somewhere else in the system, this SELECT query used in the SET returns more than one row. I'm guessing this will cause breakage or badness? True, false?
Thanks.
True. When assigning to a variable, the query must return a single row, containing a single column. You can also do it with this syntax:
SELECT someColumn INTO myVariable ... LIMIT 1;
In a sql script that does sequential execution, is there a way one can introduce an IF THEN ELSE conditional to control the flow of query execution?
I happened to run into this http://www.bennadel.com/blog/1340-MySQL-Does-Not-Support-IF-ELSE-Statements-In-General-SQL-Work-Flow.htm
which says that the IF THEN ELSE will not work in a sql script.
Is there another way around?
Basically, I want to run a particular "select colName from table" command and check if colName corresponds to a particular value. If it does, proceed with the rest of the script. Else, halt execution.
Please advise.
I just wrap my SQL script in a procedure, where conditional code is allowed. If you'd rather not leave the statements lying around, you can drop the procedure when you're done. Here's an example:
delimiter //
create procedure insert_games()
begin
set #platform_id := (select id from platform where name = 'Nintendo DS');
-- Only insert rows if the platform was found
if #platform_id is not null then
insert into game(name, platform_id) values('New Super Mario Bros', #platform_id);
insert into game(name, platform_id) values('Mario Kart DS', #platform_id);
end if;
end;
//
delimiter ;
-- Execute the procedure
call insert_games();
-- Drop the procedure
drop procedure insert_games;
If you haven't used procedures, the "delimiter" keyword might need some explanation. The first line switches the delimiter to "//" so that we can include semi-colons in our procedure definition without MySQL attempting to interpret them yet. Once the procedure has been created, we switch the delimiter back to ";" so we can execute statements as usual.
After doing some research I think I may have found a way to work around this. I was looking for a way to verify if a script had already executed against a target database. This will be primarily for version control of my databases. I have a table created to keep track of the scripts that have been executed and wanted some flow inside my scripts to check that table first before execution. While I have not completely solved the problem yet I have created a simple script that basically does what I need, I just need to wrap the DDL into the selects based on the value of the variables.
step 1 - Setup a bit variable to hold the result
step 2 - do your select and set the variable if the result is found
step 3 - Do what you need to do on false result
step 4 - Do what you need to do on true result
Here is the example script
set #schemachangeid = 0;
select #schemachangeid := 1 from SchemaChangeLog where scriptname = '1_create_tables.sql';
select 'scriptalreadyran' from dual where #schemachangeid = 1;
select 'scriptnotran' from dual where #schemachangeid = 0;
I also recognize this is an old thread but maybe this will help someone out there trying to do this kind of thing outside of a stored procedure like me.