I'm creating a MySQL stored procedure that receives the names of two views, and performs a Union upon them into the first of the two.
I've used prepared statements to take view names as strings, so I can use this stored procedure with a wealth of other stored procedures that produce views of varying names.
The following code works as expected:
DROP view if exists test1;
DROP view if exists test2;
CREATE VIEW test1 as SELECT "Cows";
CREATE VIEW test2 as SELECT "Horses";
DROP VIEW if exists tempView;
CREATE VIEW tempView AS SELECT * FROM test1 UNION SELECT * FROM test2;
SELECT * from tempView;
However, when I execute the following code:
DELIMITER //
DROP PROCEDURE IF EXISTS SP_unionViews //
CREATE PROCEDURE SP_unionViews(IN viewname varchar(255),
IN viewname2 varchar(255))
BEGIN
DROP VIEW IF EXISTS tempView;
SET #in1 = viewname;
SET #in2 = viewname2;
SET #str = 'CREATE VIEW tempView AS
SELECT * FROM ? UNION SELECT * FROM ?';
PREPARE stmt FROM #str;
EXECUTE stmt USING #in1, #in2;
SET #str2 = 'DROP VIEW ?';
SET #in3 = viewname;
PREPARE stmt2 FROM #str2;
EXECUTE stmt2 USING #in3;
SET #str3 = 'CREATE VIEW ? AS SELECT * FROM tempView';
PREPARE stmt3 FROM #str3;
EXECUTE stmt3 USING #in3;
DEALLOCATE PREPARE stmt;
DEALLOCATE PREPARE stmt2;
DEALLOCATE PREPARE stmt3;
END //
DELIMITER ;
DROP view if exists test1;
DROP view if exists test2;
CREATE VIEW test1 as SELECT "Cows";
CREATE VIEW test2 as SELECT "Horses";
CALL SP_unionViews(test1, test2);
SELECT * from test1;
I get the following error:
#1054 - Unknown column 'test1' in 'field list'
That would seem to indicate that this stored procedure is trying to use test1 as a column somewhere it's not intended to be one. But I can't figure out where.
UPDATE:
When edited as below, I expected the solution to work, but it gives me another error.
The new code reads:
DELIMITER //
DROP PROCEDURE IF EXISTS SP_unionViews //
CREATE PROCEDURE SP_unionViews(IN viewname varchar(255),
IN viewname2 varchar(255))
BEGIN
DROP VIEW IF EXISTS tempView;
SET #str = CONCAT('
CREATE VIEW tempView AS
SELECT * FROM ', viewname, ' UNION SELECT * FROM ', viewname2);
PREPARE stmt FROM #str;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #str2 = CONCAT('DROP VIEW ', viewname, ';');
PREPARE stmt2 FROM #str2;
EXECUTE stmt2;
DEALLOCATE PREPARE stmt2;
SET #str3 = CONCAT('CREATE VIEW ', viewname ,' AS SELECT * FROM tempView');
PREPARE stmt3 FROM #str3;
EXECUTE stmt3;
DEALLOCATE PREPARE stmt3;
END //
DELIMITER ;
DROP view if exists test1;
DROP view if exists test2;
CREATE VIEW test1 as SELECT "Cows";
CREATE VIEW test2 as SELECT "Horses";
CALL SP_unionViews("test1", "test2");
SELECT * from test1;
And its error reads:
#1615 - Prepared statement needs to be re-prepared
You can't use parameters for table names in a prepared statement, so you will need to put the table names into the query string before you prepare the statement. Try changing your queries to these:
SET #str = CONCAT('
CREATE VIEW tempView AS
SELECT * FROM (
SELECT * FROM ', viewname, ' UNION SELECT * FROM ', viewname2, '
)');
SET #str2 = CONCAT('DROP VIEW ', viewname);
SET #str3 = CONCAT('CREATE VIEW ', viewname, ' AS SELECT * FROM tempView');
Once you have done this you will no longer need any parameters to the EXECUTEs
Related
Is there any way in MySQL to put the name of the database into a variable?
For example, when I have a database called 'db1', can I do something like this:
set #db= 'db1';
select * from #db.mytable;
EDIT: There is another example of what I want to do:
set #dbfrom= 'db1';
set #dbto= 'db2';
insert into #dbto.mytable (col1,col2,col3) select col2,col1,col3 from #dbfrom.mytable;
With considerable effort, yes.
SET #db = 'db1';
SET #q = CONCAT('SELECT * FROM ', #db, '.mycol');
PREPARE stmt FROM #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Using Chaos' 'Prepare Statement' solution I managed to create a Stored Procedure which uses a variable database name.
Works like a charm for migrating data from one database to another with a Stored Procedure. This way the code isn't pinned to a single database.
DELIMITER $$
DROP PROCEDURE IF EXISTS `SampleProcedure` $$
CREATE PROCEDURE `SampleProcedure`(IN HubDatabaseName VARCHAR(255))
BEGIN
SET #db = HubDatabaseName;
SET #q = CONCAT('
/* Import data from Hub database to local database */
INSERT INTO `table_name_in_local_database`
SELECT
*
FROM
', #db ,'.`tablename`
');
PREPARE stmt FROM #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
If you have PHP installed you could use this script to replace the mysql variables to there actual value:
<?php
$sqlFile = 'migration.sql';
$fromDb = 'db1';
$toDb = 'db2';
echo str_replace(['#fromDb', '#toDb'], [$fromDb, $toDb], file_get_contents($sqlFile));
Goal
I want to create table as follow, the format of table name is tbl+_+date , but I want to write a procedure to create when I input a given date.
drop table if exists tbl_20200802 ;
create table tbl_20200802 (index (USERID) )
select * from a;
Try
DELIMITER //
DROP PROCEDURE IF EXISTS pro_ljj_push_pre_id;
CREATE PROCEDURE pro_ljj_push_pre_id(
IN test_date date
)
BEGIN
set #table_name=CONCAT('tbl_', test_date);
SET #t1 =CONCAT(
'drop table if exists '
,#table_name
,';'
,'\n'
,'create table ', tab_name
, ' (index (USERID))'
,'\n'
,'SELECT * FROM a');
PREPARE stmt3 FROM #t1;
EXECUTE stmt3;
DEALLOCATE PREPARE stmt3;
--
END //
DELIMITER ;
CALL pro_ljj_push_pre_id('20200802');
1054 - Unknown column 'tab_name' in 'field list'
You have some syntax error in your code,
However, the following is your desired. Change the structure of table as you want.
DELIMITER $$
DROP PROCEDURE IF EXISTS pro_ljj_push_pre_id$$
CREATE PROCEDURE pro_ljj_push_pre_id(IN test_date VARCHAR(50))
BEGIN
set #table_name=CONCAT('tbl_', test_date);
SET #t1 =CONCAT('drop table if exists ',#table_name);
SELECT #t1;
PREPARE stmt3 FROM #t1;
EXECUTE stmt3;
DEALLOCATE PREPARE stmt3;
SET #t2 =CONCAT('create table ', #table_name, ' (id INT PRIMARY KEY, name VARCHAR(30));');
SELECT #t2;
PREPARE stmt4 FROM #t2;
EXECUTE stmt4;
DEALLOCATE PREPARE stmt4;
--
END $$
DELIMITER ;
CALL pro_ljj_push_pre_id('20200802');
I'm trying the following but I'm getting the following error:
ERROR 1054 (42S22): Unknown column 'f' in 'where clause'
I'm seriously confused because f is a parameter of createtableTest...
CREATE PROCEDURE createtableTest
(
tname2 varchar(20),
f varchar(20)
)
BEGIN
DROP TABLE IF EXISTS tname2;
CREATE TABLE tname2 as SELECT * FROM data WHERE group_name like f;
END;
Since f is contains the value, a dynamic sql is needed so we can concatenate it with the original query,
DELIMITER $$
CREATE PROCEDURE createtableTest(IN tname2 varchar(20),IN f varchar(20))
BEGIN
DROP TABLE IF EXISTS tname2;
SET #sql = CONCAT('CREATE TABLE tname2 as SELECT * FROM data WHERE group_name like ''%',f,'%''');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
for example, the value of f is hello, the concatenated string will produce
CREATE TABLE tname2 as SELECT * FROM data WHERE group_name like '%hello%'
UPDATE
MySQL Prepared Statements
Aside from concatenation, you can also parameterized the value which is the best way, ex
DELIMITER $$
CREATE PROCEDURE createtableTest(IN tname2 varchar(20),IN f varchar(20))
BEGIN
DROP TABLE IF EXISTS tname2;
SET #sql = CONCAT('CREATE TABLE tname2 as SELECT * FROM data WHERE group_name like ?');
PREPARE stmt FROM #sql;
SET #val = CONCAT('%', f, '%');
EXECUTE stmt USING #val;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
Here is my code
Drop procedure if exists test//
CREATE PROCEDURE test(IN woeid VARCHAR(15))
BEGIN
SET #w1 := woeid;
SET #sql = CONCAT('CREATE OR REPLACE VIEW temp
AS
SELECT *
FROM test_table gp
WHERE gp.name =', #w1);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END//
Delimiter ;
call test('ABCD');
I am getting error as
Error code: 1054. Unknown column 'ABCD' in 'where' clause
Please help.
It sounds as though you're needlessly using views, when some other approach would be more appropriate.
However, the reason it isn't working is that you haven't quoted your string literal, so the resulting SQL contains WHERE gp.name = ABCD whereas it at very least needs to be WHERE gp.name = 'ABCD'. You can use MySQL's QUOTE() function for this purpose, but it's better to parameterise the value:
DELIMITER //
DROP PROCEDURE IF EXISTS test//
CREATE PROCEDURE test(IN woeid VARCHAR(15))
BEGIN
SET #w1:=woeid, #sql:=CONCAT('
CREATE OR REPLACE VIEW temp AS
SELECT *
FROM test_table
WHERE name = ?
');
PREPARE stmt FROM #sql;
EXECUTE stmt USING #w1;
DEALLOCATE PREPARE stmt;
SET #w1:=NULL, #sql:=NULL;
END//
DELIMITER ;
CALL test('ABCD');
If i have this:
CREATE TABLE ftable (
id INT,
fvalue VARCHAR(14)
);
INSERT INTO ftable VALUES (1,'tableB'),(2,'tableA');
CREATE TABLE tableA (
value VARCHAR(14)
);
SELECT #tmp:=fvalue FROM ftable WHERE id=2;
How do I make it so I can do this:
INSERT INTO #tmp VALUES ('buhambug');
Becuase as far I know that throws a mysql error.Can someone show me a sqlfiddle of the solution? Or maybe I'm thinking about this the wrong way?
You need to use dynamic SQL to use a variable as an object name:
SET #tmp = (SELECT fvalue FROM ftable WHERE id=2);
SET #SQL = CONCAT('INSERT INTO ',#tmp,' VALUES (''buhambug'')');
PREPARE stmt FROM #SQL;
EXECUTE stmt;
SQL FIDDLE
You can't do in static sql.
You can do it in stored procedure:
delimiter $$
drop procedure if exists test_call$$
create procedure test_call(table_in varchar(100))
begin
set #q = concat("select * from ", table_in);
PREPARE stmt FROM #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
end$$
delimiter ;
call test_call('TeableA');
drop procedure if exists test_call;
In general dynamic read from dynamic tables is not a good decision