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.
Related
I would like to know if it is possible do create a table having the auto increment start with the value of the unix timestamp (the time of create of the table), i.e.
create table something(
something_id bigint not null primary key auto_increment,
something_name varchar(10) not null,
something_random varchar(3) not null
) engine=InnoDB auto_increment=round(unix_timestamp(curtime(4)) * 1000);
Note that I can just replace auto_increment=round(unix_timestamp(curtime(4)) * 1000) with the value of select round(unix_timestamp(curtime(4)) * 1000);. But what I want is a way to do it automatically when creating my tables.
After reading mysql select section everything I tried gave me a compiler error.
Thanks.
One way could be to use a stored procedure that does this.
Procedure that receives the table creation command and concatenates (CONCAT function) the value of the expression at the end. Since the query is in string format, the Prepared Statement is used to execute it.
DELIMITER $$
DROP PROCEDURE IF EXISTS `createTable`$$
CREATE PROCEDURE createTable(IN strCreateQuery TEXT)
BEGIN
SET #query = CONCAT(strCreateQuery, " auto_increment=", ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000));
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
Once created, simply execute the procedure with the creation query of the desired table.
CALL createTable("
create table something(
something_id bigint not null primary key auto_increment,
something_name varchar(10) not null,
something_random varchar(3) not null
) engine=InnoDB");
I have a field called currentItem , this field has a trigger that calls a stored procedure (with transaction) sp_TransferData to perform some transfers of information to a worktable. If the stored procedure fails - I would like to restore the old value of currentItem - as it has not effectively changed.
I am using MySQL and I would like this logic to be in my trigger - obviously we do not want an endless loop so how do I accomplish this ?
Trigger Pseudo Code :
Call sp_TransferData(#ResultCode);
Select #ResultCode into Result;
If Result < 0 THEN
thisField Value = OLD.Value;
End If;
// EDIT 9-16-2016 13:00 //
There is only 1 Row in this table never any thing more! Column list edited for brevity.
table global_items
Id INT PK,
lsize INT,
wsize INT,
currentItem INT
Trigger is on currentItem After Update or Before I do not care which as long as it works and does not refire the trigger:
If the value has changed CALL sp_TransferData(#ResultCode);
If (SELECT #ResultCode) < 0 THEN
Reset currentItem to old value but do not cycle the trigger since we are only resetting it.
EndIf;
Just to add this is what I have in my trigger code which is not correct.
The Table definitions are supplied.
BEGIN
IF NEW.currentItem <> OLD.currentItem THEN
call sp_CurrentItemChanged(NEW.currentItem, #ResultCode, #ResultMsg);
IF ((Select #ResultCode) < 0) THEN
NEW.currentItem = OLD.currentItem;
END IF;
END IF;
END
CREATE TABLE working_table (
Id int(11) NOT NULL AUTO_INCREMENT,
Mbf float DEFAULT NULL,
Width float DEFAULT NULL,
Pulse int(11) DEFAULT NULL,
PRIMARY KEY (Id)
)
ENGINE = INNODB
AUTO_INCREMENT = 1
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
CREATE TABLE recipe (
Id int(11) NOT NULL AUTO_INCREMENT,
Name varchar(80) NOT NULL DEFAULT 'UnAssigned',
IsDefault tinyint(1) DEFAULT 0,
PRIMARY KEY (Id),
UNIQUE INDEX Id_UNIQUE (Id),
UNIQUE INDEX Name_UNIQUE (Name)
)
ENGINE = INNODB
AUTO_INCREMENT = 1
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
CREATE TABLE Packs (
Id int(11) NOT NULL AUTO_INCREMENT,
Name varchar(45) NOT NULL DEFAULT 'UNDEFINED',
Width float NOT NULL DEFAULT 0,
Pulse int(11) NOT NULL DEFAULT 0,
Mbf float NOT NULL DEFAULT 0,
RecipeID int(11) NOT NULL DEFAULT 0,
SetupID int(11) DEFAULT 1,
PRIMARY KEY (Id),
INDEX SetupID_ndx (SetupID),
INDEX FK_PackRecipeID_Recipe_ID_idx (RecipeID),
INDEX FK_RecipeID_PackS_idx (RecipeID),
CONSTRAINT FK_PackRecipeID_Recipe_ID FOREIGN KEY (RecipeID)
REFERENCES recipe (Id) ON DELETE CASCADE ON UPDATE CASCADE
)
ENGINE = INNODB
AUTO_INCREMENT = 1
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
CREATE TABLE global_items (
Id int(11) NOT NULL AUTO_INCREMENT,
PackSys_Count int(11) DEFAULT NULL,
Active_Recipe int(11) DEFAULT 1,
PRIMARY KEY (Id)
)
ENGINE = INNODB
AUTO_INCREMENT = 2
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
When global_items.Active_recipe changes the trigger fires .. The data that is moved is in packs and its related tables (brevity here) to the working_table. The global_items table is NEVER touched by anything in the lengthy Stored Procedure or any other triggers or any other sql code. It is never modified by anything internal to the SQL storage - it is touched only by an outside applications. I am not sure how I restore the value to the original value on failure of the stored procedure.
I think I might be understanding what you are getting at. But since you did not show your trigger entirely I guess, and not the Stored Proc, I just winged it and investigated.
I think the problem is that your stored proc does not have an OUT qualifier to it to make it write-able. The below works fine and I think it captures how to solve your issue.
Schema:
-- drop table global_items;
create table global_items
( Id INT primary key,
lsize INT not null,
wsize INT not null,
currentItem INT not null,
theCount int not null
);
insert global_items(Id,lsize,wsize,currentItem,theCount) VALUES
(1,1,1,100,0);
select * from global_items;
Trigger:
DROP TRIGGER IF EXISTS giBeforeUpdate;
DELIMITER $$
CREATE TRIGGER giBeforeUpdate
BEFORE UPDATE
ON global_items FOR EACH ROW
BEGIN
DECLARE tRet INT;
SET tRet=0;
SET NEW.theCount=OLD.theCount+1;
CALL uspDoSomething7(tRet);
IF tRet=1 THEN
-- stored proc said FAILURE
SET NEW.currentItem=OLD.currentItem;
END IF;
END;$$
DELIMITER ;
Stored Procedure:
DROP PROCEDURE IF EXISTS uspDoSomething7;
DELIMITER $$
CREATE PROCEDURE uspDoSomething7(OUT retVal INT)
BEGIN
DECLARE rndNum INT;
SET rndNum=FLOOR(RAND()*2)+1; -- random number 1 or 2
-- sets retVal to 1 on FAILURE
IF rndNum=2 THEN
SET retVal=1; -- FAIL
ELSE
SET retVal=0; -- SUCCESS
END IF;
END$$
DELIMITER ;
Test:
Repeatedly call this confirm that it fails roughly half the time
that is, currentItem retains its old value
but chg the update stmt below each time for the currentItem= part of it
update global_items set currentItem=410,lsize=2 where Id=1;
select * from global_items;
I have a table in mysql and I want to alter a table to allow a column to be null.
When I do describe on my mysql table, I see these things in mysql workbench:
Field Type Null Key Default Extra
I want to set Null field as YES for a particular column. Here is how I am trying which works fine but do I need to provide its data type while setting DEFAULT to NULL?
ALTER TABLE abc.xyz CHANGE hello hello int(10) unsigned DEFAULT NULL;
ALTER TABLE abc.xyz CHANGE world world int(10) unsigned DEFAULT NULL;
Is there any other way by which I can just pick column name and set default to NULL instead of using its data type as well? I don't want to provide int(10) while setting its default to NULL.
You're kind of on the wrong track. Changing the default to NULL does not "allow" the column to be null: what you need to do is drop the "NOT NULL" constraint on the column.
But to redefine the nullability of a column through script, you will have to continue to reference the datatype. You'll have to enter something like
ALTER TABLE MyTable MODIFY COLUMN this_column Int NULL;
Not sure if this applies if you're looking for a straight DDL statement, but in MySQL Workbench you can right-click on a table name, select "Alter Table..." and it will pull up a table definition GUI. From there, you can select null/not null (among all the other options) without explicitly listing the column's datatype. Just a "for what it's worth"...
This can be done with the help of dynamic statements.
Usage:
CALL sp_make_nullable('schema_name', 'table_name', 'column_name', TRUE);
Implementation:
DELIMITER $$
create procedure eval(IN var_dynamic_statement text)
BEGIN
SET #dynamic_statement := var_dynamic_statement;
PREPARE prepared_statement FROM #dynamic_statement;
EXECUTE prepared_statement;
DEALLOCATE PREPARE prepared_statement;
END;
DELIMITER ;
DELIMITER $$
create procedure sp_make_nullable(IN var_schemaname varchar(64), IN var_tablename varchar(64),
IN var_columnname VARCHAR(64), IN var_nullable BOOLEAN)
BEGIN
DECLARE var_column_type LONGTEXT DEFAULT (SELECT COLUMN_TYPE
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = var_schemaname
AND TABLE_NAME = var_tablename
AND COLUMN_NAME = var_columnname);
DECLARE var_nullable_prefix VARCHAR(64) DEFAULT '';
IF NOT var_nullable THEN
SET var_nullable_prefix := 'NOT';
end if;
CALL eval(CONCAT('
ALTER TABLE ', var_schemaname, '.', var_tablename,
' MODIFY ', var_columnname, ' ', var_nullable_prefix, ' NULL
'));
end$$
DELIMITER ;
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
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.