I already wrote a pretty complex stored procedure, but now i want to bring some dynamics into the procedures using variables. I still call myself a newbiew when it comes to sql programming, so i might be totally on the wrong way with what i'd like to achieve.
I am running the latest MySQL server 8.0.13 on windows (just for local dev).
My current idea for the stored procedure
... uses an input variable
... declares a cursor (using the var)
... create a temp table (using the var)
... iterates through the temp table
... write data to a new table
I think i understand some of the basic tools to do that but i fail again and again with handling the variable(s)
The following code shows the top part of the project where i already fail.
PROCEDURE sprProcedure (
IN vInputParameter varchar(64)
)
BEGIN
DECLARE vFinished INTEGER DEFAULT 0;
-- declare cursor
DECLARE cCursor CURSOR FOR SELECT * FROM tbltmp_(vInputParameter);
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET vFinished = 1;
-- drop / create temp table
DROP TABLE IF EXISTS (vInputParameter);
CREATE TEMPORARY TABLE tbltmp_(vInputParameter)
SELECT * FROM `tbl_DataSource`;
... did not paste any further code as i can't deal with the following issue.
I tried
... using the variable directly > variable is not resolved in DECLARE CURSOR statement
... define user-defined variable before local-variables is not allowed
... CONCAT'ed the string to build a statement and EXECUTE'ed it > does not work in the DECLAREpart of the stored procedure
At this point i am totally open to every hint or totally new ideas about how to approach this.
Thanks for any advice!
[Update]
My approach up there has some flaws and i did not understand the basic concept of temp tables for example being unique to the session. Thanks to 'D's Query' and a little more reading i now have a working stored procedure without having to deal with dynamic names of cursors and temp tables.
I dont know what actually you are focusing on but loading a dynamic tables can be possible with prepared statements in Stored Procedures but prepared statements won't work with CURSORS.
Example of Prepared statement is
SET $sql=CONCAT('SELECT * from ', var_tablename);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Related
I'm painfully new to SQL/mySQL as a whole so I'm flying blind right now so apologies.
I made a procedure in mySQL that selects a varchar data from a specific column and table, turn it into INT (contents of said column are numerical to begin with) and output its values after going through a mathematical operation as a (very simple) attempt in data masking. As follows:
CREATE PROCEDURE qdwh.mask_varchar_num2(tablename varchar(100), colname varchar (100))
BEGIN
set #a=concat('select','(','(','(','(','select',colname ,'from',tablename,')','+','0',')','+','297',')','*','5',')','as','colname');
prepare query from #a;
execute query;
deallocate prepare query;
END
but when i tried to call the procedure with the following line:
select [column] , mask_varchar_num2 ([column]) from [table];
an error "FUNCTION qdwh.mask_varchar_num2 does not exist" shows up. I wanted the script to output a select function of the column in question after the conversion to INT and the mathematical operation done to it, so i can then use this procedure in a larger script ("create table select as" kinda stuff) to convert the whole table into masked data as needed.
Is there something i am missing and what am i doing wrong? Dbeaver acknowledges the procedure script as legit so i dont know whats wrong. Thanks in advance for the advice.
Procedures are run by using call and cannot be called within a select query. To define a function, you need to use create function.
not an answer but here's what your select looks like..
set #colname='a';
set #tablename='t';
set #a=concat('select','(','(','(','(','select',#colname ,'from',#tablename,')','+','0',')','+','297',')','*','5',')','as','colname');
select #a
'select((((selectafromt)+0)+297)*5)ascolname'
missing a lot of spaces between tokens
hi friends i googled for this and find different methods use by others to prevent sql injection. i wrote in below stored procedure before finalising to follow specific method i want suggestion from you guys. which method should i follow.
below is the example of my stored procedure, in which i wrote different methods
CREATE DEFINER=`root`#`localhost` PROCEDURE `spTestSQLInjection`(pSelfId VARCHAR(100),bIntSelfId BIGINT(20))
BEGIN
SET #sSelfId = pSelfId;
-- Method:1
-- below code is for injection
SET #selectQuery = CONCAT('select * from userProfile where userId = ',#sSelfId);
PREPARE stmt FROM #selectQuery;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
-- Method:2
-- injection doesent affect below code
select * from userProfile where userId = #sSelfId;
-- Method:3
select * from userProfile where userId = bIntSelfId;
-- Method:4
SET #sSelectQuery=
'select * from userProfile where userId = ? ';
PREPARE stmtQuery FROM #sSelectQuery;
EXECUTE stmtQuery USING #sSelfId;
DEALLOCATE PREPARE stmtQuery;
END
executed below stored procedure in workbench :
1)call spTestSQLInjection('231', 231);
result : when i pass proper data then result set gives single user data for all then 4 method.
2)call spTestSQLInjection('231 OR 1=1', 231);
result : when i pass '231 OR 1=1' data then result set gives all user data for method 1 and single record for method,2,3,4.
so concluded that method1 is prone to sql injection so not to follow this method, as its dynamic query
& its advisable not to write dynamic query in stored procedure.
method2, method3 worked & gave single user record, which means this query are not prone to sql injection.
method4 is adviced by most of the developer to follow this to prevent sql injection in stored procedure. but my
live project contains 20 to 30 queries(insert/update/delete) inside a stored procedure, so writing prepared statement
for all is time consuming.
so guide me to follow which method, method2, method3, or method4
Thanking you in advance, any help will be appreciated.
Methods 2, 3, and 4 are safe from SQL injection, but method 3 is the simplest solution.
CREATE DEFINER=`root`#`localhost` PROCEDURE `spTestSQLInjection`(pSelfId VARCHAR(100), bIntSelfId BIGINT(20))
BEGIN
-- Method:3
select * from userProfile where userId = bIntSelfId;
END
There's no need to create a user-defined variable, because the procedure parameter bIntSelfId is already a variable.
There's no need to use a parameter or a prepared statement in this case, because the variable is treated only as a scalar value. It doesn't need to modify any SQL syntax, nor is it used as an identifier, so it can simply be used in the query as shown above.
This assumes your table does not have its own column with the same name of bIntSelfId. If it did, the use of that identifier would be ambiguous. It's recommended to name your parameters distinctly from any of the columns of tables you will query using that variable. Using a user-defined variable or a query parameter would also avoid the ambiguity.
Hello I'm quite new to mySQL and I'm trying to write a stored procedure. I've searched on the internet to questions alike this one but I couldn't find any results for this.
I'm trying to make search function for my webapplication where you can search in the database for results, yet there are different methods to search on (By name, last name, adres, etc). The query should also have a limit in results (1, 5, 10, 20). My idea was something like this:
CREATE PROCEDURE SelectTopResults #query varchar(60), #method varchar(20), #limited int(3)
AS
SELECT * FROM customer WHERE #method = %#query% LIMIT #limited
GO;
This doesn't run. Is this idea of the procedure correct? And how should I fix it then? Or is there another better way to do this?
Thanks in advance.
Edit:
This is to be accessed with PHP.
My idea was to write a code that basically does:
$sql = 'EXEC SelectTopResults #method = ?, #query = ?, #limited = ?;'
Edit 2:
Solved, thanks a lot! :)
For those interested in the code:
DELIMITER //
CREATE PROCEDURE selectTopResults(IN col varchar(64), IN limited int(3), searchquery varchar(60))
BEGIN
SET #s = CONCAT("SELECT * FROM customer WHERE ",col," LIKE '%",searchquery,"%' LIMIT ",limited);
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
//
DELIMITER ;
Also works with wildcards and can be called upon with:
CALL selectTopResults('column_name', 5, 'query');
whereby 5 is the limit
Welcome to the forum. You've got it a bit wrong - there is something about stored procedures in the MySQL manual, but I can never find it in the first attempt. Luckily, there are many tutorials, if you search for them in google, bing or whatever. Try this, for example: https://www.mysqltutorial.org/introduction-to-sql-stored-procedures.aspx
So, to get your procedure to work:
DELIMITER $$
CREATE PROCEDURE SelectTopResults (
query varchar(60),
method varchar(20),
limited int(3)
)
BEGIN
...
END$$
DELIMITER ;
It is normal to use the DELIMITER statement to change what signifies the end of a statement - otherwise, you are going to get error messages when you type in the statements that go into the procedure. Next, you need round brackets around your parameters and no # before their names.
You may wonder why I break the parameter list out over several lines; this is just my style - I feel it makes it easier to read where the parameters start and end. Finally, about your SELECT statement:
SELECT * FROM customer WHERE #method = %#query% LIMIT #limited
I'm not sure what you are trying here - firstly, you need to loose the #s - that is for variables you set with SET, I believe (I'm writing from memory, as I am not near my manuals), not for variables and parameters in a procedure or function. But more importantly, you can't use the parameter method as the name of a table column - for that you need to construct the SELECT as a string and execute. This is called 'dynamic SQL', as far as I recall; I think you can do this in MySQL, but I am not sure without looking it up.
I hope this helps, and hopefully somebody with more immediate knowledge can help you better.
Of course, I could go into mysql console and type the Function. But what if I want to store it for future use? What do I do?
Most projects have an SQL file to initialize the database from scratch. This way, one can set up the application database by simply running this SQL file. Your CREATE PROCEDURE/FUNCTION query would also go in this file.
There's a good tutorial here:
http://www.databasejournal.com/features/mysql/article.php/3525581/MySQL-Stored-Procedures-Part-1.htm
You need to use stored procedures. Once written, these are stored in the database along with your tables. They can be invoked using the CALL <procedure> statement.
Here's an example procedure that populates table1 with random values:
DELIMITER //
DROP PROCEDURE IF EXISTS autofill//
CREATE PROCEDURE autofill()
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i < 20000 DO
INSERT INTO table1 (size) VALUES (FLOOR((RAND() * 1000)));
SET i = i + 1;
END WHILE;
END;
//
DELIMITER ;
Once the procedure has been written, it is called like this:
CALL autofill();
I need to use a native sql query in Hibernate with use of variable.
But hibernate throws an error saying: Space is not allowed after parameter prefix
So there is a conflict with the := mysql variable assignment and hibernate variable assignment.
Here is my sql query:
SET #rank:=0;
UPDATE Rank SET rank_Level=#rank:=#rank+1 ORDER BY Level;
the hibernate code (jpa syntax):
Query query = em.createNativeQuery(theQuery);
query.executeUpdate();
I can't use a stored procedure because my sql query is dynamically generated ('Level' can be 'int' or 'force'...)
How can I do this ?
thanks
Well, I finally use stored procedure (yes, what I don't want initially) to create dynamic query (I don't think it was possible).
Here is my code:
The stored procedure:
DELIMITER |
DROP PROCEDURE IF EXISTS UpdateRank |
CREATE PROCEDURE UpdateRank(IN shortcut varchar(30))
BEGIN
SET #rank=0;
SET #query=CONCAT('UPDATE Rank SET ', shortcut, '=#rank:=#rank+1 ORDER BY ', shortcut);
PREPARE q1 FROM #query;
EXECUTE q1;
DEALLOCATE PREPARE q1;
END;
|
DELIMITER ;
The tip is the use of the CONCAT function to dynamically create a query in the stored procedure.
Then, call the procedure in classic hibernate function:
Query q = em.createNativeQuery("CALL updateRank('lvl')");
q.executeUpdate();
I'll copy paste my answer from https://stackoverflow.com/a/25552002/3987202
Another solution for those of us who can't make the jump to Hibernate 4.1.3.
Simply use /*'*/:=/*'*/ inside the query. Hibernate code treats everything between ' as a string (ignores it). MySQL on the other hand will ignore everything inside a blockquote and will evaluate the whole expression to an assignement operator.
I know it's quick and dirty, but it get's the job done without stored procedures, interceptors etc.
Use MySQL Proxy to rewrite the query after Hibernate has sent the query to the database.
For example supply Hibernate with this,
UPDATE Rank SET rank_Level=incr(#rank) ORDER BY Level;
but rewrite it to this,
UPDATE Rank SET rank_Level=#rank:=#rank+1 ORDER BY Level;