I have a stored procedure in MySQL that calls a function that inserts values into a table.
The insert statement is like
INSERT INTO Table1 SELECT * from Table2
Table2 has a variable name, depending on the date the procedure is called, like
table_201410 , if the procedure was called in October 2014. Soevery month, the procedure should make the select from another table.
I have read some answers about preparing and executing, however as I am new to MySQL/Programming. I am a bit lost.
You can use a prepared statement like this:
DELIMITER $$
DROP PROCEDURE copy_table $$
CREATE PROCEDURE copy_table ()
BEGIN
set #table_name = date_format(now(),'%Y%m'); -- getting year and month
-- concatenating
set #sql = concat('INSERT INTO Table1 SELECT * from table_',#table_name);
-- creating a prepared statement and executing
PREPARE insert_stmt FROM #sql;
EXECUTE insert_stmt;
DEALLOCATE PREPARE insert_stmt;
END$$
DELIMITER ;
Related
Consider the following stored procedure and its usage:
DROP PROCEDURE IF EXISTS ShowMIHoles;
DELIMITER $$
CREATE PROCEDURE ShowMIHoles(IN CourseID VARCHAR(255))
BEGIN
select * from tblcourses where id=CourseID;
END $$
DELIMITER ;
call ShowMIHoles(1299)
That works, and returns the row of table tblcourses with id 1299.
However, it isn't protected from SQL injection.
So, I read that quote() should be used to make a value safe.
This is my attempt to use quote:
DROP PROCEDURE IF EXISTS ShowMIHoles;
DELIMITER $$
CREATE PROCEDURE ShowMIHoles(IN CourseID VARCHAR(255))
BEGIN
select * from tblcourses where id=quote(CourseID);
END $$
DELIMITER ;
call ShowMIHoles(1299)
That results in "0 rows returned". No error message. MySQL 5.7.28.
I tried various tests to see what was going wrong. The ones that don't use CourseID parameter, I tested both inside procedure, and as a stand-alone query.
select quote(1299);
=> '1299'
select * from tblcourses where id='1299';
=> The expected row with id 1299.
select * from tblcourses where id=quote(1299);
=> 0 rows returned.
It is possible to make this work, via prepared statement:
...
BEGIN
SET #sql = CONCAT('select * from tblcourses where id=', quote(CourseID));
prepare stmt from #sql;
execute stmt;
END $$
...
=> The expected row with id 1299.
Question:
Is there any way to safely use this parameter as an expression value in the where clause, without dynamically preparing a statement?
You do not need to worry about SQL injection inside a stored procedure unless you are using dynamic SQL. Strings will always be treated like whole string and numbers as numbers.
So, the first version you are showing is perfectly fine. Just make sure that when you call the procedure, your code is safe.
I have main_table:
SELECT PORT_ID, DATA from main_table
i need run trigger AFTER INSERT main_table which sort DATA to the other tables:
INSERT INTO #PORT_ID (DATA) VALUE (#DATA)
return an error message:
dynamic sql is not allowed in stored function or trigger resolved.
Any idea?
Many thanks
Workarround
I do a simply workarround, 1, save a SQL query into new table as a whole text. 2, run an EVENT per second with EXECUTE saved query
This is to big for a comment.
A simple Procedure that only executes the insert as prepared statement
CREATE DEFINER=`root`#`localhost` PROCEDURE `procedure_stmt`(IN test TEXT)
BEGIN
SET #sql = test;
PREPARE stmt2 FROM #sql;
EXECUTE stmt2;
END
ANd as a trigger
BEGIN
SET #sql = CONCAT('INSERT INTO ','gps_', NEW.PORT,' (DATA) VALUES (',NEW.DATTA,')');
CALL procedure_stmt(#sql);
END$$
DELIMITER ;
If you had posted tables and data i would have tested it further.
There are two tables
1.FinalTable(f1,f2,f3,f4)
2.DemoTable_1(d1,d2,d3,d4)
I want to insert data from DemoTable_1 to FinalTable using the following SQL query:
INSERT INTO `FinalTable`
(`f1`,`f2`,`f3`,`f4`)
(SELECT `d1`,`d2`,`d3`,`d4`
FROM DemoTable_1);
So I want to create the procedure by passing DemoTable_1 as a parameter for the procedure.
So I can change the source table as DemoTable_2, DemoTable_3, DemoTable_4 and so on..
I am using SQLyog community
DELIMITER //
CREATE OR REPLACE PROCEDURE FinalTable_insert(IN source_table VARCHAR(40))
BEGIN
INSERT INTO `FinalTable`
(`f1`,`f2`,`f3`,`f4`)
(SELECT `d1`,`d2`,`d3`,`d4`
FROM source_table);
END //
DELIMITER ;
CALL FinalTable_insert('DemoTable_1');
Error Code: 1146
Table 'source_table' doesn't exist
The input variables doesn't evaluate as table names, you must build a query in a string and execute that using prepared statement:
DELIMITER //
DROP PROCEDURE IF EXISTS FinalTable_insert //
CREATE PROCEDURE FinalTable_insert(IN source_table VARCHAR(40))
BEGIN
SET #sql = CONCAT("INSERT INTO `FinalTable`
(`f1`,`f2`,`f3`,`f4`)
SELECT `d1`,`d2`,`d3`,`d4`
FROM `",source_table,"`");
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END //
DELIMITER ;
In MySQL, I have a number of procedures which are more or less identical - they all perform the same (or very similar) operations, but they perform it on different tables.
I'd like to reduce these to one procedure, parameterized by table name, if possible. For example, suppose I wanted to execute a generic select:
SELECT * FROM TableFor("TableName")
Is this (or anything similar) possible in MySQL? Is it possible in any SQL dialect?
Per Tomva's Answer
A full example:
DROP PROCEDURE IF EXISTS example;
CREATE PROCEDURE example(IN tablename VARCHAR(1000)) BEGIN
SET #statement = CONCAT('SELECT * FROM ', #tablename);
PREPARE statement FROM #statement;
EXECUTE statement;
DEALLOCATE PREPARE statement;
END;
CALL example('tablename');
You can do this with a prepared statement.
It will be something along the lines of
SET #stat = CONCAT('SELECT * FROM ', #tab');
PREPARE stat1 FROM #stat;
EXECUTE stat1;
DEALLOCATE PREPARE stat1;
Dynamic SQL does not work in a function, so make a Stored Procedure from this, and you will be able to provide the table parameter.
I am going to assume you know what a stored procedure is (I hope you do otherwise my answer will be useless)
First create a table object in your procedure
declare #tablenames table(name varchar)
insert into #MonthsSale (name) values ('firsttable')
insert into #MonthsSale (name) values ('secondtable')
...
You can add this little line to suppress the rows affected messages:
SET NOCOUNT ON
Then create a cursor for this table and a variable to save your table name
DECLARE #TABLENAME VARCHAR
DECLARE tables_cursor CURSOR FOR SELECT name FROM #tablenames
Then loop through cursor and execute your code for each table name
OPEN Tables_cursor
FETCH NEXT FROM Tables_cursor INTO #Tablename
WHILE ##FETCH_STATUS = 0
BEGIN
YOUR CODE USING THE #Tablename
END
CLOSE Tables_cursor
DEALLOCATE Tables_cursor
hey lets say we have 3 tables tbl1,tbl2,tbl3 and using the below query you can view the data
select * from tbl1
select * from tbl2
select * from tbl3
my question is that can you eliminate repetition by using variables? like for example
DECLARE #x as varchar(60)
set #x = tbl1
set #x = tbl2
set #x = tbl3
select * from #x
Go
I hate retyping the exact query does anyone know a way to make the query work I think it would save me loads of time. thanks
Why not create a stored procedure for that?
Example:
DELIMITER $$
DROP PROCEDURE IF EXISTS `selectAllTables`$$
CREATE PROCEDURE `selectAllTables`()
BEGIN
SELECT * from tbl1;
SELECT * from tbl2;
SELECT * from tbl3;
END$$
DELIMITER ;
Usage:
CALL `selectAllTables`();
If you meant Dynamic SQL (SQL Server) type of support in MySQL, you may achieve this using prepare statement in stored procedure
First create a stored procedure with a parameter to take table name in string:
DELIMITER ///
CREATE PROCEDURE SelectAllRecords(__TABLE__NAME varchar(255))
BEGIN
SET #sql = CONCAT('SELECT * FROM ', __TABLE__NAME);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END///
DELIMITER ;
Next, you may CALL the stored procedure sending in the table name:
call SelectAllRecords('table1')
call SelectAllRecords('table2')
call SelectAllRecords('table3')
If i got your Question right then the below Query will work for you.
DECLARE #x as table
set #x = select * from tbl3
select * from #x
Go