I want to be able to create some stored Procedures in different databases - so I want to be able to pass in the database name into the stored procedure creation statement.
SET #SourceDBName='dev';
DELIMITER //
CREATE PROCEDURE test ()
BEGIN
USE #SourceDBName;
SELECT * FROM agreed_relation;
END //
DELIMITER ;
How can I pass #SourceDBName into the CREATE PROCEDURE statement?
to pass in the database name into a stored procedure you must declare it in the procedure like this:
DELIMITER //
CREATE PROCEDURE test (IN idbname VARCHAR(20))
BEGIN
SELECT * FROM agreed_relation WHERE dbname = idbname;
END //
DELIMITER ;
After you create a Table like this where 'dbname' field it's the one your procedure will call:
create table agreed_relation
(
dbname varchar(30) not null
);
After insert some values you call the procedure and pass any dbname to the SELECT statament:
insert into agreed_relation(dbname) values('Oracle');
insert into agreed_relation(dbname) values('Mysql');
insert into agreed_relation(dbname) values('Mongodb');
Calling procedure and passing some value:
CALL test('Mysql');
14.1.16 CREATE PROCEDURE and CREATE FUNCTION Syntax
...
USE statements within stored routines are not permitted. When a
routine is invoked, an implicit USE db_name is performed (and undone
when the routine terminates). The causes the routine to have the given
default database while it executes. References to objects in databases
other than the routine default database should be qualified with the
appropriate database name.
...
An option to create the stored procedure in different databases is:
FIle: /path/to/file/myProcedure.sql
DROP PROCEDURE IF EXISTS `test`;
DELIMITER //
CREATE PROCEDURE `test`()
BEGIN
SELECT * FROM `agreed_relation`;
END//
DELIMITER ;
MySQL Command-Line:
mysql> USE `dev`;
Database changed
mysql> \. /path/to/file/myProcedure.sql
Query OK, 0 rows affected (0.00 sec)
mysql> USE `db1`;
Database changed
mysql> \. /path/to/file/myProcedure.sql
Query OK, 0 rows affected (0.00 sec)
mysql> USE `db2`;
Database changed
mysql> \. /path/to/file/myProcedure.sql
Query OK, 0 rows affected (0.00 sec)
mysql> USE `dev`;
Database changed
mysql> CALL `test`;
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> USE `db1`;
Database changed
mysql> CALL `test`;
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> USE `db2`;
Database changed
mysql> CALL `test`;
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
You can also create the stored procedure in a single database and pass the database name as a parameter to qualified the required objects and use 14.5 Prepared SQL Statement Syntax to execute it:
mysql> USE `dev`;
Database changed
mysql> DROP PROCEDURE IF EXISTS `test`;
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> CREATE PROCEDURE `test`(`db_name` VARCHAR(64))
-> BEGIN
-> SET `db_name` := TRIM('\'' FROM QUOTE(`db_name`));
-> SET #`query` := CONCAT('SELECT * FROM `', `db_name`, '`.`agreed_relation`');
-> PREPARE `stmt` FROM #`query`;
-> EXECUTE `stmt`;
-> DEALLOCATE PREPARE `stmt`;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CALL `test`('dev');
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> CALL `test`('db1');
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> CALL `test`('db2');
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
Related
On current MySql DB server, i have two schemas: "Friends", "Places". Entire DB is organized around stored procedures which are being called from outside. Maybe it's good approach, maybe it's bad but it's not related to this problem i'm having. In this case DB has to be separated from any outside software using it (as i'm only in charge of DB).
Some stored procedures from "Friends" schema refer to tables from "Places" and vice versa. Now, if for example i wanna setup new set of schemas, on the same server, but for another "client" like this:
Friends_clientOne
Places_clientOne
Friends_clientTwo
Places_clientTwo
I'm having a problem - stored procedures referring tables from another schema won't know which schema name to use. Checking and modifying each and every procedure to suite appropriate schema name every time new set is created is not an option. Dynamic SQL is totally new for me - what are other options? How can i, for example, do this:
(stored procedure inside schema Friends_clientOne):
Select * from Places_<getCurrentSchemaSuffix>.someTable;
Please tell me MySql is flexible enough for this :( What about Percona?
The closest thing to what you're describing is a builtin function DATABASE() (http://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_database), which returns the current default database.
The default database isn't necessarily the one that a given table belongs to. It's the database most recently named in a USE <databasename> statement. If you can rely on your application always using the database you mean for that table to belong to, then you can use that function.
However, no SQL implementation allows you to change the table name dynamically during query execution. You can name tables only before doing the prepare of a statement, and hard-coding it into the query. There is no syntax for making the table name variable.
So you'll have to use dynamic SQL even if you use the DATABASE() function.
Percona Server is no different from stock Oracle MySQL for this problem.
Your options for this problem are:
Stop using multiple schemas for each client. Put all of the data for each client into a single schema. This seems simplest.
Design the stored procedures to be unique to each client. You said you didn't want to do this. But for what it's worth, we do this in the stored procedures and triggers in the customer databases I manage at my current job. It's not that bad. We have a "template" version of the CREATE statements for each trigger or procedure, with a placeholder token for the customer ID. When we create a new customer's database, we copy that template code and make a substitution on the customer ID placeholder, then run it.
Put each of your clients' data into their own exclusive instance of MySQL Server. This way you can have multiple schemas per client, but the schema names don't need to be distinct for each client. You can run multiple instances on one server host, they just have to be configured with distinct datadir, port, sock_file, and other log files. Though I have seen this solution used, I don't recommend it, because it has a lot of resource overhead, and it's hard to manage.
Learn to use dynamic SQL.
You can use PREPARED Statement in the Procs like this:
DELIMITER //
CREATE PROCEDURE getPlace (OUT param1 char)
BEGIN
SELECT CONCAT("Select * from Places_", SUBSTRING_INDEX(DATABASE(), '_', -1),".someTable;") INTO #sql;
PREPARE getPlaces from #sql;
EXECUTE getPlaces;
DEALLOCATE PREPARE getPlaces;
END;
//
DELIMITER ;
sample
MariaDB [mysql]> CREATE DATABASE Friends_clientOne;
Query OK, 1 row affected (0.00 sec)
MariaDB [mysql]> CREATE DATABASE Friends_clientTwo;
Query OK, 1 row affected (0.00 sec)
MariaDB [mysql]> CREATE DATABASE Places_clientOne;
Query OK, 1 row affected (0.00 sec)
MariaDB [mysql]> CREATE DATABASE Places_clientTWO;
Query OK, 1 row affected (0.00 sec)
MariaDB [mysql]> CREATE TABLE Places_clientOne.someTable (name varchar(32));
Query OK, 0 rows affected (0.02 sec)
MariaDB [mysql]> CREATE TABLE Places_clientTwo.someTable (name varchar(32));
Query OK, 0 rows affected (0.02 sec)
MariaDB [mysql]> INSERT INTO Places_clientOne.someTable VALUES('text in Places_clientOne.someTable');
Query OK, 1 row affected, 1 warning (0.00 sec)
MariaDB [mysql]> INSERT INTO Places_clientTwo.someTable VALUES('text in Places_clientTwo.someTable');
Query OK, 1 row affected, 1 warning (0.01 sec)
MariaDB [mysql]> use Friends_clientOne;
Database changed
MariaDB [Friends_clientOne]> DELIMITER //
MariaDB [Friends_clientOne]> CREATE PROCEDURE getPlace (OUT param1 char)
-> BEGIN
-> SELECT CONCAT("Select * from Places_", SUBSTRING_INDEX(DATABASE(), '_', -1),".someTable;") INTO #sql;
-> PREPARE getPlaces from #sql;
-> EXECUTE getPlaces;
-> DEALLOCATE PREPARE getPlaces;
-> END;
-> //
Query OK, 0 rows affected (0.03 sec)
MariaDB [Friends_clientOne]> DELIMITER ;
MariaDB [(none)]> use Friends_clientTwo;
Database changed
MariaDB [Friends_clientTwo]> DELIMITER //
MariaDB [Friends_clientTwo]>
MariaDB [Friends_clientTwo]> CREATE PROCEDURE getPlace (OUT param1 char)
-> BEGIN
-> SELECT CONCAT("Select * from Places_", SUBSTRING_INDEX(DATABASE(), '_', -1),".someTable;") INTO #sql;
-> PREPARE getPlaces from #sql;
-> EXECUTE getPlaces;
-> DEALLOCATE PREPARE getPlaces;
-> END;
-> //
Query OK, 0 rows affected (0.02 sec)
MariaDB [Friends_clientTwo]> DELIMITER ;
MariaDB [Friends_clientTwo]> call getPlace(#r);
+----------------------------------+
| name |
+----------------------------------+
| text in Places_clientTwo.someTab |
+----------------------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
MariaDB [Friends_clientTwo]> use Friends_clientOne;
Database changed
MariaDB [Friends_clientOne]> call getPlace(#r);
+----------------------------------+
| name |
+----------------------------------+
| text in Places_clientOne.someTab |
+----------------------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
MariaDB [Friends_clientOne]>
I am trying to create event for one of my database using below code,
use testing;
show events;
show warnings;
set global event_scheduler =on;
DELIMITER $$
create event table_backup_testingTo_test on schedule every 1 day
starts '2015-10-14 16:40:00'
do
select * into test.event_table_testing from testing.manitest;
DELIMITER $$
After run this code if i check in show events then there is no event in the name of table_backup_testingTo_test
where am i doing mistake?
Note : I am using mysql workbench 6.3
You change the delimiter, but actually never finish a statement with it. And after the multiple statements you should change the delimiter back to default. In your case you don't need a delimiter at all, since it's just one statement. Try like this:
DELIMITER ; /*assuming it's still set to $$*/
use testing;
show events;
show warnings;
set global event_scheduler =on;
create event table_backup_testingTo_test on schedule every 1 day
starts '2015-10-14 16:40:00'
do
select * into test.event_table_testing from testing.manitest;
Or, if you have multiple statements in your event:
use testing;
show events;
show warnings;
set global event_scheduler =on;
DELIMITER $$
create event table_backup_testingTo_test on schedule every 1 day
starts '2015-10-14 16:40:00'
do
begin
select * into test.event_table_testing from testing.manitest;
select 'we have multiple statements here';
end $$
DELIMITER ;
My test:
mysql> CREATE DATABASE `testing`;
Query OK, 1 row affected (0.00 sec)
mysql> USE `testing`;
Database changed
mysql> CREATE TABLE `manitest` (
-> `column_0` int,
-> `column_1` varchar(7),
-> `column_2` varchar(55)
-> );
mysql> INSERT INTO `manitest`
-> (`column_0`, `column_1`, `column_2`)
-> VALUES
-> (1, 'value_1_0', 'value_2_0'),
-> (2, 'value_1_1', 'value_2_1'),
-> (3, 'value_1_2', 'value_2_2');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> CREATE DATABASE `test`;
Query OK, 1 row affected (0.00 sec)
mysql> USE `test`;
Database changed
mysql> CREATE TABLE `event_table_testing` (
-> `column_0` int,
-> `column_1` varchar(7),
-> `column_2` varchar(55)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * INTO `test`.`event_table_testing`
-> FROM `testing`.`manitest`;
ERROR 1327 (42000): Undeclared variable: test
mysql> INSERT INTO `test`.`event_table_testing`
-> SELECT * FROM `testing`.`manitest`;
Query OK, 3 rows affected (0.00 sec)
mysql> CREATE EVENT `table_backup_testingTo_test` ON SCHEDULE EVERY 1 DAY
-> STARTS '2015-10-14 16:40:00'
-> DO
-> -- select * into test.event_table_testing from testing.manitest;
-> INSERT INTO `test`.`event_table_testing`
-> SELECT * FROM `testing`.`manitest`;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW EVENTS\G
*************************** 1. row ***************************
Db: test
Name: table_backup_testingTo_test
.
.
.
1 row in set (0.00 sec)
I am creating procedure in mysql. but I am facing some issues while creating that.
I am applying query i.e
CREATE PROCEDURE simpleproc( param1 INT) BEGIN SELECT COUNT(*)
INTO param1 FROM 91_nidhi; END//
and The error is
#1064 - You have an error in your SQL syntax; c
heck the manual that corresponds to your MySQL server version for the
right syntax to use near '' at line 1
This how you need to do
- You are not passing any input value rather you are using an output value
- so specify the param as OUT
Below is the example
mysql> create table 91_nidhi (id int,val varchar(20));
Query OK, 0 rows affected (0.09 sec)
mysql> insert into 91_nidhi values (1,'aa'),(2,'bb'),(3,'cc');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
Now lets create the procedure
delimiter //
CREATE PROCEDURE simpleproc( out param1 INT)
BEGIN
SELECT COUNT(*) INTO param1 FROM 91_nidhi;
END; //
Then change the delimiter in the terminal as
mysql> delimiter ;
Now lets call the procedure
mysql> call simpleproc(#res);
Query OK, 0 rows affected (0.00 sec)
mysql> select #res ;
+------+
| #res |
+------+
| 3 |
+------+
1 row in set (0.00 sec)
mySql :
Your SQL query has been executed successfully
0 rows affected by the last statement inside the procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `update_adm`(OUT `sp_out` INT(11), IN `sp_email` VARCHAR(50) CHARSET utf8)
NO SQL
BEGIN
UPDATE `admin` SET `last_try`=curtime() WHERE `email`=sp_email;
SET sp_out=ROW_COUNT();
END
why 0 rows affected by the last statement inside the procedure ?!
edited :
When I replace sp_email with correct value like navid#yahoo.com in my stored procedure, it works perfectly !
CREATE DEFINER=`root`#`localhost` PROCEDURE `update_adm`()
NO SQL
BEGIN
UPDATE `admin` SET `last_try`=curtime() WHERE `email`='navid#yahoo.com';
END
From the MySQL command line, the output is as expected.
mysql> delimiter $$
mysql> CREATE DEFINER=`root`#`localhost PROCEDURE update_adm( ...
-> END$$
Query OK, 0 rows affected (0.16 sec)
mysql> delimiter ;
mysql> insert into admin values (null,'foo');
Query OK, 1 row affected (0.00 sec)
mysql> call update_adm(#cnt,'foo');
Query OK, 1 row affected (0.00 sec)
mysql> call update_adm(#cnt,'bar');
Query OK, 0 rows affected (0.00 sec)
When I call the procedure with an email that exists, I get a message back showing 1 row was affected. When I call the procedure with an email that does exist, it returns a message back showing 0 rows affected.
I believe the message you are seeing is from the client interface. What client are you using to call the procedure?
After inputting the triggers, the console seems in an odd state where normal commands are not responded to. Am I inadvertently doing that with the delimiter?
mysql> use nntp;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+---------------------+
| Tables_in_nntp |
+---------------------+
| articles |
| newsgroups |
| newsgroups_articles |
+---------------------+
3 rows in set (0.00 sec)
mysql> show triggers;
Empty set (0.00 sec)
mysql> DELIMITER $$
mysql> USE `nntp`$$
Database changed
mysql> CREATE
-> TRIGGER `nntp.newsgroups.before_insert`
-> BEFORE INSERT ON `nntp`.`newsgroups`
-> FOR EACH ROW
-> BEGIN
-> set new.hash = md5(new.newsgroup);
-> END$$
Query OK, 0 rows affected (0.18 sec)
mysql> DELIMITER $$
mysql> USE `nntp`$$
Database changed
mysql> CREATE
-> TRIGGER `nntp.newsgroups.before_update`
-> BEFORE UPDATE ON `nntp`.`newsgroups`
-> FOR EACH ROW
-> BEGIN
-> set new.hash = md5(new.newsgroup);
-> END$$
Query OK, 0 rows affected (0.19 sec)
mysql> show triggers;
-> ^CCtrl-C -- exit!
Aborted
thufir#dur:~$
You need to change the delimiter back when you're done creating a trigger or routine, otherwise you'll have to use the same delimiter (in this case $$) for all statements subsequently.
For example:
mysql> DELIMITER $$
mysql> USE `nntp`$$
Database changed
mysql> CREATE
-> TRIGGER `nntp.newsgroups.before_update`
-> BEFORE UPDATE ON `nntp`.`newsgroups`
-> FOR EACH ROW
-> BEGIN
-> set new.hash = md5(new.newsgroup);
-> END$$
Query OK, 0 rows affected (0.19 sec)
mysql> DELIMITER ;
mysql> show triggers;
Note the second use of the DELIMITER keyword.