I need to change a lot default values of the DB structure for new entries in MULTIPLE tables to have this new default value in DB I tried to use something like this:
SET #money_rename_def := 20*10000;
SET #money_gender_def := 40*10000;
ALTER TABLE `money` CHANGE `money_rename` `money_rename` int(10) UNSIGNED NOT NULL DEFAULT '#money_rename_def',
CHANGE `money_gender` `money_gender` int(10) UNSIGNED NOT NULL DEFAULT '#money_gender_def';
But the SET prefix does not fork for alter table command. Is there any way how to do this to use pre-defined value so I can only change it once in SET or simillar definition?
I tried to search documentation but maybe just missed it?
You can use dynamic query like this:
DROP PROCEDURE IF EXISTS `tableDefaultSetter`$$
CREATE PROCEDURE `tableDefaultSetter`()
BEGIN
SET #default1 = 20;
SET #query = concat('ALTER TABLE `ttestt` CHANGE `val` `val` int NOT NULL DEFAULT ', #default1);
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
Sample Data:
DROP TABLE IF EXISTS ttestt;
CREATE TABLE ttestt
(
id INT,
val INT(10) DEFAULT 10
);
INSERT INTO ttestt (id)
VALUES (1);
CALL tableDefaultSetter();
INSERT INTO ttestt (id)
VALUES (1);
SELECT *
FROM ttestt;
Result:
1,10
1,20
So the first item had 10 as default value and second item has been changed to 20. You see that it works.
For multiple values, you cannot put multiple queries inside one statement:
Doc
The text must represent a single statement, not multiple statements.
So you can create another procedure for convenience:
DELIMITER $$
DROP PROCEDURE IF EXISTS `exec_query`$$
CREATE PROCEDURE `exec_query`(queryStr TEXT)
BEGIN
SET #query = queryStr;
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DROP PROCEDURE IF EXISTS `tableDefaultSetter`$$
CREATE PROCEDURE `tableDefaultSetter`()
BEGIN
SET #default1 = 20;
SET #default2 = 30;
SET #default3 = 40;
SET #default4 = 50;
CALL exec_query(concat('ALTER TABLE `ttestt` CHANGE `val` `val` int NOT NULL DEFAULT ', #default1));
CALL exec_query(concat('ALTER TABLE `ttestt2` CHANGE `val` `val` int NOT NULL DEFAULT ', #default2));
CALL exec_query(concat('ALTER TABLE `ttestt3` CHANGE `val` `val` int NOT NULL DEFAULT ', #default3));
CALL exec_query(concat('ALTER TABLE `ttestt4` CHANGE `val` `val` int NOT NULL DEFAULT ', #default4));
END$$
DELIMITER ;
Use it like this:
CALL tableDefaultSetter();
DROP PROCEDURE `tableDefaultSetter`;
DROP PROCEDURE `exec_query`;
Related
I have a table with design
CREATE TABLE IF NOT EXISTS InsuranceContract (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`enquiryCode` VARCHAR(20) DEFAULT NULL,
`contractCode` VARCHAR(20) DEFAULT NULL,
`createdAt` DATETIME DEFAULT CURRENT_TIMESTAMP (),
`updatedAt` DATETIME DEFAULT CURRENT_TIMESTAMP () ON UPDATE CURRENT_TIMESTAMP (),
UNIQUE KEY (`enquiryCode`)) ENGINE=INNODB DEFAULT CHARSET=UTF8 COLLATE = UTF8_BIN;
Then I was created a procedure like this
DROP procedure IF EXISTS `sp_insurance_contract_get`;
DELIMITER $$
CREATE PROCEDURE `sp_insurance_contract_get` (enquiryCode VARCHAR(20), contractCode VARCHAR(20))
BEGIN
SET #t1 = "SELECT * FROM InsuranceContract
WHERE InsuranceContract.enquiryCode = enquiryCode
AND InsuranceContract.contractCode = contractCode;";
PREPARE param_stmt FROM #t1;
EXECUTE param_stmt;
DEALLOCATE PREPARE param_stmt;
END$$
DELIMITER ;
And I was executed this procedure in MySQL Workbench by this command:
CALL sp_insurance_contract_get('EQ000000000014', '3001002');
I expected I will receive 1 row result but it selected all records in this table.
If I copy and create exactly this #t1 into plain SQL not using statement, it's correct.
Please help me to fix this error. I'm using MySQL 8.0.19
You can use placehoders on prepare statements, this is why we use them to prevent sql injection
One other thing never use column names as variables names, databases can not differentiate
DROP procedure IF EXISTS `sp_insurance_contract_get`;
DELIMITER $$
CREATE PROCEDURE `sp_insurance_contract_get` (enquiryCode_ VARCHAR(20), contractCode_ VARCHAR(20))
BEGIN
SET #t1 = "SELECT * FROM InsuranceContract
WHERE enquiryCode = ?
AND contractCode = ?;";
PREPARE param_stmt FROM #t1;
SET #a = enquiryCode_;
SET #b = contractCode_;
EXECUTE param_stmt USING #a, #b;
DEALLOCATE PREPARE param_stmt;
END$$
DELIMITER ;
When you say
WHERE enquiryCode = enquiryCode
you compare that named column to itself. The result is true always (unless the column value is NULL).
Change the names of your SP's parameters, so you can say something like
WHERE enquiryCode_param = enquiryCode
and things should work.
Notice that you have no need of a MySql "prepared statement" here. In the MySql / MariaDb world prepared statements are used for dynamic SQL. That's for constructing statements within the server from text strings. You don't need to do that here.
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 shared server where i have 50 to 60 databases each database has 200 tables.
How to add few new column's on all the existing databases in one go instead of one database after another manually?
ALTER TABLE `users` ADD `a` VARCHAR( 200 ) NULL;
ALTER TABLE `users` ADD `b` VARCHAR( 200 ) NULL;
ALTER TABLE `users` ADD `c` VARCHAR( 200 ) NULL;
ALTER TABLE `users` ADD `d` VARCHAR( 200 ) NULL;
ALTER TABLE `users` ADD `e` VARCHAR( 200 ) NULL;
ALTER TABLE `users` ADD `f` VARCHAR( 200 ) NULL;
You can create procedure for the same. And in procedure you can wrote cursor on this query.
select TABLE_NAME from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='sampledata';
Make dynamic ALTER statement using Dynamic Query:
DELIMITER $$
CREATE PROCEDURE `SAMPLEPROCEDURE`(IN COLUMNNAME VARCHAR(40))
BEGIN
DECLARE VAR_TABLENAME VARCHAR(100);
DECLARE DONE INT;
DECLARE CUR CURSOR FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'SAMPLEDATA';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET DONE=1;
SET DONE = 0;
OPEN CUR;
TABLELOOP: LOOP
FETCH CUR INTO VAR_TABLENAME;
IF DONE = 1 THEN LEAVE TABLELOOP; END IF;
SET #VAR_ALTER_QUERY =CONCAT("ALTER TABLE ",VAR_TABLENAME," ADD ",COLUMNNAME," VARCHAR(200) NULL");
PREPARE STMT FROM #VAR_ALTER_QUERY;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
END LOOP TABLELOOP;
END
You can took above procedure as reference for same.
use information_schema
select
case when table_schema is not null then
CONCAT("USE ",TABLE_SCHEMA) end use_schema ,
CONCAT("Alter Table '", TABLE_SCHEMA,"'.'", TABLE_NAME, " Add 'a' varchar(200)") as MySQLCMD
from TABLES
where table_name = 'USERS';
The point is that you could use the dictionary schema to retrieve each 'user' tables from each schema and generate the ALTER scripts.
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 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.