MYSQL stored procedure create dynamic table from date - mysql

I'm facing a little problem to create the table name dynamically.
For example ,
This query (SELECT DATE_FORMAT(NOW(),'%Y%m')) returns 201702
My motive is to check whether the table exist.
If it doesn't exist , it will create it automatically.
Now here's my problem.
messages_`,datereturn
It seems I'm getting error for even compiling. How do we pass parameter to create the table?
Really appreciate your help.
Full Code:
BEGIN
SET datereturn = (SELECT DATE_FORMAT(NOW(),'%Y%m'));
CREATE TABLE IF NOT EXISTS `messages_`,datereturn (
`mid` bigint(17) NOT NULL,
`uid` int(11) NOT NULL,
`csid` int(11) NOT NULL,
`content` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`content_type` tinyint(4) NOT NULL,
`datecreated` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`datecreated1` bigint(13) DEFAULT NULL,
PRIMARY KEY (`mid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
END
EDIT: it's different than the answer proposed.
I'm making the table dynamic with MySQL 5.6.
The above suggested thread doesn't work for my version.
So, I don't know why it's a possible of duplicate.

Stored procedures don't allow you to combine variables into SQL identifiers. In other words, things like table names must be set before the query is parsed.
So you need to create a dynamic SQL statement and make the stored procedure prepare the CREATE TABLE statement at runtime:
BEGIN
SET #sql = CONCAT('CREATE TABLE IF NOT EXISTS messages_',datereturn,' (',
'mid bigint NOT NULL, ',
'uid int NOT NULL, ',
'csid int NOT NULL, ',
'content varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, ',
'content_type tinyint NOT NULL, ',
'datecreated timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, ',
'datecreated1 bigint DEFAULT NULL, ',
'PRIMARY KEY (mid)',
') ENGINE=InnoDB DEFAULT CHARSET=latin1');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
(Note: I have not tested this code, so if I missed a quote, I expect you know how to fix that.)
In this example, I also removed your back-ticks because they're not necessary, and I removed the length options for int types because they have no effect.
All that said, I have to question why you need a table per date. Seems like a code smell to me. Have you considered creating a table partitioned by date instead?

SET #CrtTbl = CONCAT('CREATE TABLE', CONCAT('`messages_', datererun), '(mid bigint(17) NOT NULL, .... and so on
...
PREPARE CrtTblStmt FROM #CrtTbl;
EXECUTE CrtTblStmt;
DEALLOCATE PREPARE CrtTblStmt;
something like that

Related

MySQL conditionally create a table

Is it possible to do a conditional create table in MySql based on the result of a select statement? Essentially, if I have a schema used by multiple clients but only some of them need a table can I create it based on another value...for example...if I have a user John then Create this table...because John's app needs it.
Something along the lines of:
IF EXISTS (SELECT * FROM USERS WHERE name='JOHN')
CREATE TABLE CREATE_THIS
(
ID VARCHAR(255) COLLATE utf8_bin NOT NULL,
NAME VARCHAR(255) COLLATE utf8_bin NOT NULL
)
ENGINE=MyISAM DEFAULT CHARSET=utf8;
This sort of business logic does not really belong within the database layer of your application. It would normally reside at a higher level, within whatever code you use to connect to the database.
However, for completeness, there is a (very hackish) way to accomplish what you ask by preparing a statement from a string that contains the SQL to be executed:
SET #sql := CASE WHEN EXISTS (SELECT * FROM USERS WHERE name='JOHN') THEN
'CREATE TABLE CREATE_THIS (
ID VARCHAR(255) COLLATE utf8_bin NOT NULL,
NAME VARCHAR(255) COLLATE utf8_bin NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8'
END;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
You can also use
CREATE Table IF NOT EXISTS <Table_Name> ( ....
...)

MySQL Update Query Successfull But Values Doesn't Changing At All

I have a problem, I created a stored procedure to activate users by sending their email id and activation key
this is the SQL syntax (in MySQL)
DELIMITER $$
CREATE PROCEDURE `dbname`.`sp_userActivate` (
IN email VARCHAR(140),
IN ac VARCHAR(64)
)
BEGIN
SET SQL_SAFE_UPDATES=0;
UPDATE user SET activated = 1
WHERE user.email = email AND
user.activation_key=ac;
commit;
END
When I execute the syntax, it's successfully executed, but when I take a look in the table, the value activated still remains = 0 (not updated at all)
I have looked more than twice to ensure the email and activation is equal with is stored in table,
What's wrong with this Query?
UPDATE
This is my table structure in schema
Thanks in advance for your help.
SQL Statement for Create table
CREATE TABLE IF NOT EXISTS `db`.`user` (
`no` INT(11) NOT NULL AUTO_INCREMENT ,
`username` VARCHAR(140) NOT NULL ,
`password` VARCHAR(128) NOT NULL ,
`firstname` VARCHAR(300) NOT NULL ,
`lastname` VARCHAR(300) NULL DEFAULT NULL ,
`email` VARCHAR(140) NOT NULL ,
`pepper` CHAR(128) NOT NULL ,
`activation_key` VARCHAR(64) NULL DEFAULT NULL ,
`gender` CHAR(1) NULL DEFAULT NULL ,
`activated` CHAR(1) CHARACTER SET 'latin1' COLLATE 'latin1_bin' NULL DEFAULT '0' ,
PRIMARY KEY (`no`) ,
UNIQUE INDEX `username` (`username` ASC) ,
UNIQUE INDEX `email` (`email` ASC) ,
INDEX `user_firstname_idx` (`firstname` ASC) ,
INDEX `user_lastname_idx` (`lastname` ASC) )
For Example Row
insert into
user(username, password,firstname, lastname, email,pepper,activation_key,gender)
values("usr1test","c781bf44a464a5946ef36a7250f5504388914bbf6287fabaf938472f46c413d71cd7bf2b3077eeac8675419d5f022ff3652ba7e13e8","user1","test","usr1test#localhost","af41bfa3c9324f39fd82f84125967b38969662256cf8249e73e3bd2cef3928b5","OGE4Y2E2OWUtMmM2Mi00MjJkLWI0NTQtNzJkZDQ1OTcxNjUx",'M');
Here is the procedure, that worked for me:
DROP PROCEDURE IF EXISTS sp_userActivate;
DELIMITER $$
CREATE PROCEDURE sp_userActivate (
IN email VARCHAR(140),
IN ac VARCHAR(64)
)
BEGIN
SET SQL_SAFE_UPDATES=0;
UPDATE `user`
SET activated = 1
WHERE
`user`.`email` = email
AND
`user`.`activation_key` = ac;
COMMIT;
END $$
DELIMITER ;
Run this, then try:
CALL sp_userActivate('usr1test#localhost',
'OGE4Y2E2OWUtMmM2Mi00MjJkLWI0NTQtNzJkZDQ1OTcxNjUx');
It worked correctly on my machine.
okay, after see the table data in my table. It seems that the key is have BLANK space after the last character.
example :
-- with blank space:
ZWRhNzZmMzMtMmI2Ny00NDBlLTkxNTUtNmQ2MWIwYjg3MzA4_ (see _ ?)
-- without blank space: ZWRhNzZmMzMtMmI2Ny00NDBlLTkxNTUtNmQ2MWIwYjg3MzA4
so, the MySQL see point no 1 and 2 are different.
I hope this makes my problem clear.
thank you for all of the contributor

MySQL variable table naming creation

I am creating a database for a collection of servers for minecraft, and the way I have it set up, I want a table to be created for each server as it is added. At the moment, I have everything working except for the fact that i cannot get the tables that are being created to contain the IP address. I want the table to be something like [IP]_Players where the [IP] is replaced by the actual IP address, which will be send through the function that it is being created through. Here is what I have so far:
DELIMITER $$
CREATE PROCEDURE `minecraft`.`AddServer` (ip Text)
BEGIN
DECLARE play TEXT;
DECLARE tran TEXT;
SET play = ip + '_Players';
SET tran = ip + '_Transactions';
INSERT INTO `minecraft`.`Server_Data` (`Server_IP`) VALUES (ip);
CREATE TABLE `minecraft`.play (
`Player` TEXT NOT NULL ,
`Balance` DOUBLE NOT NULL DEFAULT 100 ,
`Warnings` INT NOT NULL DEFAULT 0 ,
`Offences` INT NOT NULL DEFAULT 0 ,
UNIQUE INDEX `Player_UNIQUE` (`Player` ASC) );
CREATE TABLE `minecraft`.tran (
`Time` TIMESTAMP NOT NULL ,
`Player` TEXT NOT NULL ,
`Destination` TEXT NOT NULL ,
`Amount` DOUBLE NOT NULL ,
`Description` TEXT NOT NULL ,
PRIMARY KEY (`Time`) );
END
Instead of creating it as 192.168.001.107_Players when
CALL minecraft.AddServer('192.168.001.107');
is preformed, it creates a table called play.
What am I doing wrong?
I was playing around and got this to work. Note that you cannot have periods in a table name. So you may want to use the REPLACE function to replace the periods with underscores for example.
DELIMITER $$
CREATE PROCEDURE `minecraft`.`AddServer` (ip Text)
BEGIN
DECLARE play varchar(500);
DECLARE STMT varchar(500);
SET play = CONCAT(ip, '_Players');
SET #sql_stmt = CONCAT('CREATE TABLE minecraft.', play, ' (
`Player` VARCHAR(50) NOT NULL ,
`Balance` DOUBLE NOT NULL DEFAULT 100 ,
`Warnings` INT NOT NULL DEFAULT 0 ,
`Offences` INT NOT NULL DEFAULT 0 ,
UNIQUE INDEX `Player_UNIQUE` (`Player` ASC) );');
PREPARE STMT FROM #sql_stmt;
EXECUTE STMT;
END$$
Delimiter ;
You have to use prepared statements I guess
SQL Syntax Prepared Statements.

Operand should contain 1 column(s)

Getting a Operand should contain 1 column(s) mysql error whenever I try to insert into the table sets.
I googled and found a hoard of similar questions but they are always pin point specific to solving their immediate problem. I have mysql 5.6 by the way. I am allowed multiple TIMESTAMPS.
Here is my code:
INSERT INTO `sets` (`tabler_name`) VALUES ("leads_auto");
Here is my table:
CREATE TABLE IF NOT EXISTS `lms`.`sets` (
`set_id` BIGINT NOT NULL AUTO_INCREMENT,
`on_off` SMALLINT NOT NULL DEFAULT 0,
`tabler_name` VARCHAR(45) NULL,
`origin_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_modified_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`original_count` INT NULL,
`current_count` INT NULL,
`source_type` VARCHAR(45) NULL,
`source` VARCHAR(45) NULL,
`method` VARCHAR(45) NULL,
`agent` VARCHAR(45) NULL,
`dupes` INT NULL,
`bads` INT NULL,
`aged` INT NULL COMMENT 'This table keeps track of the record sets that enter the system. Example: a set of leads imported into the database.',
PRIMARY KEY (`set_id`)
) ENGINE = InnoDB;
Stored Procedure:
DELIMITER //
CREATE PROCEDURE `lms`.`leads_to_bak` ()
BEGIN
SET #table1 = (SELECT `tabler_name` FROM sets WHERE on_off=0 LIMIT 1);
SET #table2 = CONCAT(#table1, '_bak');
SET #SQL1 = CONCAT('INSERT INTO ',#table2, '(', (SELECT
REPLACE(GROUP_CONCAT(COLUMN_NAME), 'lead_id,', '') FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #table2), ')', ' SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), 'lead_id,', '') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #table1), ' FROM ', #table1);
PREPARE stmt FROM #sql1;
EXECUTE stmt;
END//
DELIMITER ;
USE `lms`;
Trigger
DELIMITER $$
USE `lms`$$
CREATE TRIGGER `lms`.`after_insert_into_leads`
AFTER INSERT ON `sets` FOR EACH ROW
BEGIN
IF (SELECT * FROM sets WHERE on_off=0 LIMIT 1) THEN
CALL lms.leads_to_bak();
END IF;
END$$
DELIMITER ;
USE `lms`;
I don't see anything wrong with my routines. Removing the routines and trigger seems to make the problem go away.
In your trigger, did you mean to put EXISTS after IF? Like this:
CREATE TRIGGER `lms`.`after_insert_into_leads`
AFTER INSERT ON `sets` FOR EACH ROW
BEGIN
IF EXISTS (SELECT * FROM sets WHERE on_off=0 LIMIT 1) THEN
CALL lms.leads_to_bak();
END IF;
END$$
Escape your table name, it seems to be a reserved function. I'm not sure if you've defined one locally.
INSERT INTO `sets` (tabler_name) VALUES ("leads_auto");
Also, you can't have two timestamp fields in a single database afaik. Change one of the two timestamps to a DATETIME field if it caused you issues as well
Besides escaping the field name in your INSERT-statement, it cannot be improved very much. But it doesn't generate any error in my test enviroment. Is this really the exact statement throwing you an error?
However, there's a slight problem in your table definition, it will throw you an
Incorrect table definition; there can be only one TIMESTAMP column
with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause.
As the error message indicates, you can only use one timestamp column with CURRENT_TIMESTAMP, if you need more than one, you can do this using a trigger.

Mysql Prepare Statement error while executing

I am trying to create a table though prepare statement but it is giving me syntax error. Well if I try to execute the same statement individually then it works fine.
Here's my statement -
SET #Stmt1 = Concat('DROP TABLE IF EXISTS ',DB,'.`county`;\n'
'CREATE TABLE IF NOT EXISTS ',DB,'.`County`
(
`CountyID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`CountyName` VARCHAR(45) NOT NULL,
`CountyCode` VARCHAR(30) NOT NULL,
PRIMARY KEY (`CountyID`)
)');
Prepare stmt2 From #stmt1;
Execute stmt2;
Please can anyone tell me what am I missing in this statement?
It is giving me an error on this line:
'CREATE TABLE IF NOT EXISTS ',DB,'.`County`
(
`CountyID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
http://dev.mysql.com/doc/refman/5.1/en/prepare.html says:
The text [of the preparable statement] must represent a single SQL statement, not multiple statements.
So you'll have to execute your DROP TABLE statement first, and then prepare and execute the CREATE TABLE statement separately.
are you not missing a comma between the two strings in the concat?
should be
SET #Stmt1 = Concat('DROP TABLE IF EXISTS ',DB,'.county;\n', 'CREATE TABLE IF NOT EXISTS ',DB,'.County ( CountyID INT UNSIGNED NOT NULL AUTO_INCREMENT, CountyName VARCHAR(45) NOT NULL, CountyCode VARCHAR(30) NOT NULL, PRIMARY KEY (CountyID) )');