I'm trying to create a store procedure to add a column on a table.
when i use this code(like below),I want to create a column with name like 'newColumn' that I can name when I call procedure. But when I call procedure the column added but not with my name newColumn but with column name x!!
Thank you.
DELIMITER //
CREATE PROCEDURE addColumn(x varchar(20))
BEGIN
alter table proc
add column x varchar(20) not null;
END //
DELIMITER ;
call addColumn('newColumn');
Form the query using concat of the various parts and execute it.
CREATE PROCEDURE addColumn(x varchar(20))
BEGIN
SET #STMT = CONCAT("alter table proc add column ", x, " varchar(20) not null");
PREPARE S FROM #STMT;
EXECUTE S;
DEALLOCATE PREPARE S;
END
But as mentioned in comments, this is dangerous - it can lead to SQL Injection attacks and other problems. At the very least, please sanitize x as much as possible.
Related
I have several MySQL tables that maintains a tree structure of records. Each record have an ID and a Parent field. I want to write a stored function to get the parent ID, given a record ID.
The following is my first attempt, and it's incorrect. My problem is I do not know how to use variable table name.
delimiter $$
create function parent(
tableName varchar(15),
nodeId int
) returns int
begin
declare p int;
select parent into p from tableName where id=nodeId;
return p;
end$$
Please help. Thanks!
After some research, apparently a stored function will not work in this case due to the fact stored functions cannot execute dynamic SQL. I change my implementation to a stored procedure.
delimiter $$
create procedure parent(tableName varchar(15), nodeId int)
begin
set #s := concat('select parent from ', tableName, ' where id =', nodeId);
prepare query from #s;
execute query;
deallocate prepare query;
end$$
delimiter ;
I've written a stored procedure function to get a name from a table. The trouble is that I want the table name to be passed in as a parameter (there are several different tables I need to use this function with):
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `getName`(tableName VARCHAR(50), myId INT(11)) RETURNS VARCHAR(50)
begin
DECLARE myName VARCHAR(50);
SELECT
'name' INTO myName
FROM
tableName
WHERE
id=myId;
RETURN myName;
end
This method has an error because it uses the variable name "tableName" instead of the actual value of the variable.
I can work around this problem in a procedure by using a CONCAT like this:
SET #GetName = CONCAT("
SELECT
'name'
FROM
",tableName,"
WHERE
id=",myId,";
");
PREPARE stmt FROM #GetName;
EXECUTE stmt;
...but, when I try to do this in a function I get a message saying:
Dynamic SQL is not allowed in stored function or trigger
I tried to use a procedure instead, but I couldn't get it to just return a value, like a function does.
So, can anyone see a way to get around this problem. It seems incredibly basic really.
If you want to buld a SQL statement using identifiers, then you need to use prepared statements; but prepared statements cannot be used in functions. So, you can create a stored procedure with OUT parameter -
CREATE PROCEDURE getName
(IN tableName VARCHAR(50), IN myId INT(11), OUT myName VARCHAR(50))
BEGIN
SET #GetName =
CONCAT('SELECT name INTO #var1 FROM ', tableName, ' WHERE id=', myId);
PREPARE stmt FROM #GetName;
EXECUTE stmt;
SET myName = #var1;
END
Using example -
SET #tableName = 'tbl';
SET #myId = 1005;
SET #name = NULL;
CALL getName(#tableName, #myId, #name);
SELECT #name;
I've written a stored procedure. It's working fine except taking the table name as input parameter.
Let see my proc in MySQL:
DELIMITER $$
USE `db_test`$$
DROP PROCEDURE IF EXISTS test_proc$$
CREATE DEFINER=`root`#`localhost`
PROCEDURE `test_proc`(IN serviceName VARCHAR(10),IN newsInfoTable VARCHAR(100))
BEGIN
SELECT COUNT(*) FROM newsInfoTable WHERE newsServiceName=serviceName;
END$$
DELIMITER ;
Stored procedure calling parameters:
USE db_test;
CALL test_proc('abc','tbl_test_news');
Here the service name parameter is working fine. But if I include the newsInfoTable variable as table input parameter then a error shows.
Table 'db_test.newsinfotable' doesn't exist
Why does this happen only for table parameter? How can I retrieve from this error or
How I pass a table name into a stored procedure as a parameter?
An SP cannot be optimized with a dynamic table name, so many DBs, MySQL included, don't allow table names to be specified dynamically.
One way around this is to use Dynamic SQL.
CREATE DEFINER=`root`#`localhost` PROCEDURE `test_proc`(IN serviceName VARCHAR(10),IN newsInfoTable VARCHAR(100))
BEGIN
SET #sql = CONCAT('SELECT COUNT(*) FROM ',newsInfoTable,' WHERE newsServiceName=?;');
PREPARE s1 from #sql;
SET #paramA = serviceName;
EXECUTE s1 USING #paramA;
END$$
You can use EXECUTE IMMEDIATE for a "less is more" solution (for me, less code = good)
CREATE PROCEDURE test_proc(IN serviceName VARCHAR(10), IN newsInfoTable VARCHAR(100))
BEGIN
EXECUTE IMMEDIATE CONCAT('SELECT COUNT(*) FROM ',newsInfoTable,' WHERE newsServiceName=''', serviceName, '''');
END
that part of a query cannot be dynamic.
you may consider implementing as a string that is executed dynamically at runtime
Although may not be what you want, alternatively, can consider to use conditionally if and prepare the statement.
DELIMITER $$
CREATE PROCEDURE select_count(IN table_name VARCHAR(20))
BEGIN
IF table_name = 'xxx' THEN
SELECT * FROM xxx;
ELSEIF table_name = 'yyy' THEN
...
ENDIF
END$$
I want to dynamically create table from my program with columns name and table name given by me through my program. so i want to pass my variable to the stored procedure but error occurs as i do like this
create procedure maketable
#name varchar(50),
#roll int
as
begin
create table new (#name, #roll)
end
error is as follow
Msg 102, Level 15, State 1, Procedure maketable, Line 7
Incorrect syntax near '#name'.
You're out of luck, MySQL stored procedures can not contain dynamic SQL, and the variable implementation can't be used how you're trying to use it.
Because you know all of the column information in your calling code, is there a specific reason you can't just issue the CREATE TABLE directly from your code? That would be the most straightforward way to get this done. (Mind you, having non-temporary tables spring into existence on demand is probably a bad, bad idea...)
Here's a start - this creates a table with one field so you should be able to finish it off:
DROP PROCEDURE IF EXISTS maketable;
delimiter //
CREATE PROCEDURE maketable (IN table_name varchar(50), IN field1Name varchar(50), IN field1Type varchar(50))
BEGIN
SET #s = CONCAT('CREATE TABLE ', table_name, '(', field1Name, ' ', field1Type, ')');
PREPARE stmt1 FROM #s;
EXECUTE stmt1;
END//
delimiter ;
CALL maketable('tst', 'id', 'INT');
I have a need to sync auto_increment fields between two tables in different databases on the same MySQL server. The hope was to create a stored procedure where the permissions of the admin would let the web user run ALTER TABLE [db1].[table] AUTO_INCREMENT = [num]; without giving it permissions (That just smells of SQL injection).
My problem is I'm receiving errors when creating the store procedure. Is this something that is not allowed by MySQL?
DROP PROCEDURE IF EXISTS sync_auto_increment;
CREATE PROCEDURE set_auto_increment (tableName VARCHAR(64), inc INT)
BEGIN
ALTER TABLE tableName AUTO_INCREMENT = inc;
END;
To extend on the discussion on the comments on Chibu's answer... yes, you can use prepared statements. But you got to use CONCAT to create the sentence instead of using PREPARE ... FROM ....
Here is a working solution:
DROP PROCEDURE IF EXISTS set_auto_increment;
DELIMITER //
CREATE PROCEDURE set_auto_increment (_table VARCHAR(64), _inc INT)
BEGIN
DECLARE _stmt VARCHAR(1024);
SET #SQL := CONCAT('ALTER TABLE ', _table, ' AUTO_INCREMENT = ', _inc);
PREPARE _stmt FROM #SQL;
EXECUTE _stmt;
DEALLOCATE PREPARE _stmt;
END//
DELIMITER;
I've learned this form the article Prepared Statement Failure by Michael McLaughlin.
The problem seems to be that you need to change the delimiter. It thinks that the Alter table line is the end of the function. Try this:
DROP PROCEDURE IF EXISTS sync_auto_increment;
DELIMITER //
CREATE PROCEDURE set_auto_increment (tableName VARCHAR(64), inc INT)
BEGIN
ALTER TABLE tableName AUTO_INCREMENT = inc;
END//
DELIMITER ;
Sometimes mysql is still picky about letting you use stored procedures, so you can do try this if you still can't run it:
DROP PROCEDURE IF EXISTS sync_auto_increment;
DELIMITER //
CREATE PROCEDURE set_auto_increment (tableName VARCHAR(64), inc INT)
DETERMINISTIC
READS SQL DATA
BEGIN
ALTER TABLE tableName AUTO_INCREMENT = inc;
END//
DELIMITER ;
I think you'll find you can't put Data Definition Language statements into a stored procedure. A possible exception would be CREATE TEMPORARY TABLE. I have searched the MySQL manual for more information on that point; it says the stored procedure may contain a statement_list, but nowhere defines what that means. But I think that's the case.