I have this code:
ALTER TABLE `settings`
ADD COLUMN `multi_user` TINYINT(1) NOT NULL DEFAULT 1
And I want to alter this table only if this column doesn't exist.
I'm trying a lot of different ways, but nothing works:
ALTER TABLE `settings`
ADD COLUMN IF NOT EXISTS `multi_user` TINYINT(1) NOT NULL DEFAULT 1
With procedure:
DELIMITER $$
CREATE PROCEDURE Alter_Table()
BEGIN
DECLARE _count INT;
SET _count = ( SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'settings' AND
COLUMN_NAME = 'multi_user');
IF _count = 0 THEN
ALTER TABLE `settings` ADD COLUMN `multi_user` TINYINT(1) NOT NULL DEFAULT 1
END IF;
END $$
DELIMITER ;
I got error in END IF, then in END and then in 1
How can I make this as simple as possible?
Use the following in a stored procedure:
IF NOT EXISTS( SELECT NULL
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'tablename'
AND table_schema = 'db_name'
AND column_name = 'columnname') THEN
ALTER TABLE `TableName` ADD `ColumnName` int(1) NOT NULL default '0';
END IF;
Use PREPARE/EXECUTE and querying the schema.
The host doesn't need to have permission to create or run procedures :
SET #dbname = DATABASE();
SET #tablename = "tableName";
SET #columnname = "colName";
SET #preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = #tablename)
AND (table_schema = #dbname)
AND (column_name = #columnname)
) > 0,
"SELECT 1",
CONCAT("ALTER TABLE ", #tablename, " ADD ", #columnname, " INT(11);")
));
PREPARE alterIfNotExists FROM #preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
Here is a solution that does not involve querying INFORMATION_SCHEMA, it simply ignores the error if the column does exist.
DROP PROCEDURE IF EXISTS `?`;
DELIMITER //
CREATE PROCEDURE `?`()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
ALTER TABLE `table_name` ADD COLUMN `column_name` INTEGER;
END //
DELIMITER ;
CALL `?`();
DROP PROCEDURE `?`;
P.S. Feel free to give it other name rather than ?
Add field if not exist:
CALL addFieldIfNotExists ('settings', 'multi_user', 'TINYINT(1) NOT NULL DEFAULT 1');
addFieldIfNotExists code:
DELIMITER $$
DROP PROCEDURE IF EXISTS addFieldIfNotExists
$$
DROP FUNCTION IF EXISTS isFieldExisting
$$
CREATE FUNCTION isFieldExisting (table_name_IN VARCHAR(100), field_name_IN VARCHAR(100))
RETURNS INT
RETURN (
SELECT COUNT(COLUMN_NAME)
FROM INFORMATION_SCHEMA.columns
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = table_name_IN
AND COLUMN_NAME = field_name_IN
)
$$
CREATE PROCEDURE addFieldIfNotExists (
IN table_name_IN VARCHAR(100)
, IN field_name_IN VARCHAR(100)
, IN field_definition_IN VARCHAR(100)
)
BEGIN
SET #isFieldThere = isFieldExisting(table_name_IN, field_name_IN);
IF (#isFieldThere = 0) THEN
SET #ddl = CONCAT('ALTER TABLE ', table_name_IN);
SET #ddl = CONCAT(#ddl, ' ', 'ADD COLUMN') ;
SET #ddl = CONCAT(#ddl, ' ', field_name_IN);
SET #ddl = CONCAT(#ddl, ' ', field_definition_IN);
PREPARE stmt FROM #ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END;
$$
this is not original, but it IS copy-and-paste
source: javajon.blogspot.com/2012/10/
I used this approach (Without using stored procedure):
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'tbl_name' AND COLUMN_NAME = 'column_name'
If it didnt return any rows then the column doesn't exists then alter the table:
ALTER TABLE tbl_name
ADD COLUMN column_name TINYINT(1) NOT NULL DEFAULT 1
Hope this helps.
hope this will help you
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'tbl_name'
AND table_schema = 'db_name'
AND column_name = 'column_name'
or
delimiter '//'
CREATE PROCEDURE addcol() BEGIN
IF NOT EXISTS(
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME='new_column' AND TABLE_NAME='tablename' AND TABLE_SCHEMA='the_schema'
)
THEN
ALTER TABLE `the_schema`.`the_table`
ADD COLUMN `new_column` TINYINT(1) NOT NULL DEFAULT 1;;
END IF;
END;
//
delimiter ';'
CALL addcol();
DROP PROCEDURE addcol;
$sql="SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Your_Table_Name' AND COLUMN_NAME = 'Your_New_Column_Name'";
$RESULT = mysqli_query($conn,$sql);
The abobe query return 0 if the column is not present in your table then you need to run alter query like below
if($RESULT){
$sqll="ALTER TABLE Your_table_Name ADD COLUMN Your_New_Column_Name varchar(20) NOT NULL DEFAULT 0";
}
SET #dbname = DATABASE();
SET #tablename = "table";
SET #columnname = "fieldname";
SET #preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = #tablename)
AND (table_schema = #dbname)
AND (column_name = #columnname)
) > 0,
"SELECT 1",
CONCAT("ALTER TABLE ", #tablename, " ADD ", #columnname, " DECIMAL(18,4) NULL;")
));
PREPARE alterIfNotExists FROM #preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
This below worked for me:
SELECT count(*)
INTO #exist
FROM information_schema.columns
WHERE table_schema = 'mydatabase'
and COLUMN_NAME = 'mycolumn'
AND table_name = 'mytable' LIMIT 1;
set #query = IF(#exist <= 0, 'ALTER TABLE mydatabase.`mytable` ADD COLUMN `mycolumn` MEDIUMTEXT NULL',
'select \'Column Exists\' status');
prepare stmt from #query;
EXECUTE stmt;
Sometimes it may happen that there are multiple schema created in a database.
So to be specific schema we need to target, so this will help to do it.
SELECT count(*) into #colCnt FROM information_schema.columns WHERE table_name = 'mytable' AND column_name = 'mycolumn' and table_schema = DATABASE();
IF #colCnt = 0 THEN
ALTER TABLE `mytable` ADD COLUMN `mycolumn` VARCHAR(20) DEFAULT NULL;
END IF;
Using this as an example:
https://dbabulletin.com/index.php/2018/03/29/best-practices-using-flyway-for-database-migrations/
DELIMITER $$
DROP PROCEDURE IF EXISTS upgrade_database_4_to_5 $$
CREATE PROCEDURE upgrade_database_4_to_5()
BEGIN
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
AND COLUMN_NAME='multi_user' AND TABLE_NAME='settings') ) THEN
ALTER TABLE `settings` ADD COLUMN `multi_user` TINYINT(1) NOT NULL DEFAULT 1;
END IF;
END $$
CALL upgrade_database_4_to_5() $$
DELIMITER ;
Related
I have this code:
ALTER TABLE `settings`
ADD COLUMN `multi_user` TINYINT(1) NOT NULL DEFAULT 1
And I want to alter this table only if this column doesn't exist.
I'm trying a lot of different ways, but nothing works:
ALTER TABLE `settings`
ADD COLUMN IF NOT EXISTS `multi_user` TINYINT(1) NOT NULL DEFAULT 1
With procedure:
DELIMITER $$
CREATE PROCEDURE Alter_Table()
BEGIN
DECLARE _count INT;
SET _count = ( SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'settings' AND
COLUMN_NAME = 'multi_user');
IF _count = 0 THEN
ALTER TABLE `settings` ADD COLUMN `multi_user` TINYINT(1) NOT NULL DEFAULT 1
END IF;
END $$
DELIMITER ;
I got error in END IF, then in END and then in 1
How can I make this as simple as possible?
Use the following in a stored procedure:
IF NOT EXISTS( SELECT NULL
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'tablename'
AND table_schema = 'db_name'
AND column_name = 'columnname') THEN
ALTER TABLE `TableName` ADD `ColumnName` int(1) NOT NULL default '0';
END IF;
Use PREPARE/EXECUTE and querying the schema.
The host doesn't need to have permission to create or run procedures :
SET #dbname = DATABASE();
SET #tablename = "tableName";
SET #columnname = "colName";
SET #preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = #tablename)
AND (table_schema = #dbname)
AND (column_name = #columnname)
) > 0,
"SELECT 1",
CONCAT("ALTER TABLE ", #tablename, " ADD ", #columnname, " INT(11);")
));
PREPARE alterIfNotExists FROM #preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
Here is a solution that does not involve querying INFORMATION_SCHEMA, it simply ignores the error if the column does exist.
DROP PROCEDURE IF EXISTS `?`;
DELIMITER //
CREATE PROCEDURE `?`()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
ALTER TABLE `table_name` ADD COLUMN `column_name` INTEGER;
END //
DELIMITER ;
CALL `?`();
DROP PROCEDURE `?`;
P.S. Feel free to give it other name rather than ?
Add field if not exist:
CALL addFieldIfNotExists ('settings', 'multi_user', 'TINYINT(1) NOT NULL DEFAULT 1');
addFieldIfNotExists code:
DELIMITER $$
DROP PROCEDURE IF EXISTS addFieldIfNotExists
$$
DROP FUNCTION IF EXISTS isFieldExisting
$$
CREATE FUNCTION isFieldExisting (table_name_IN VARCHAR(100), field_name_IN VARCHAR(100))
RETURNS INT
RETURN (
SELECT COUNT(COLUMN_NAME)
FROM INFORMATION_SCHEMA.columns
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = table_name_IN
AND COLUMN_NAME = field_name_IN
)
$$
CREATE PROCEDURE addFieldIfNotExists (
IN table_name_IN VARCHAR(100)
, IN field_name_IN VARCHAR(100)
, IN field_definition_IN VARCHAR(100)
)
BEGIN
SET #isFieldThere = isFieldExisting(table_name_IN, field_name_IN);
IF (#isFieldThere = 0) THEN
SET #ddl = CONCAT('ALTER TABLE ', table_name_IN);
SET #ddl = CONCAT(#ddl, ' ', 'ADD COLUMN') ;
SET #ddl = CONCAT(#ddl, ' ', field_name_IN);
SET #ddl = CONCAT(#ddl, ' ', field_definition_IN);
PREPARE stmt FROM #ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END;
$$
this is not original, but it IS copy-and-paste
source: javajon.blogspot.com/2012/10/
I used this approach (Without using stored procedure):
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'tbl_name' AND COLUMN_NAME = 'column_name'
If it didnt return any rows then the column doesn't exists then alter the table:
ALTER TABLE tbl_name
ADD COLUMN column_name TINYINT(1) NOT NULL DEFAULT 1
Hope this helps.
hope this will help you
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'tbl_name'
AND table_schema = 'db_name'
AND column_name = 'column_name'
or
delimiter '//'
CREATE PROCEDURE addcol() BEGIN
IF NOT EXISTS(
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME='new_column' AND TABLE_NAME='tablename' AND TABLE_SCHEMA='the_schema'
)
THEN
ALTER TABLE `the_schema`.`the_table`
ADD COLUMN `new_column` TINYINT(1) NOT NULL DEFAULT 1;;
END IF;
END;
//
delimiter ';'
CALL addcol();
DROP PROCEDURE addcol;
$sql="SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Your_Table_Name' AND COLUMN_NAME = 'Your_New_Column_Name'";
$RESULT = mysqli_query($conn,$sql);
The abobe query return 0 if the column is not present in your table then you need to run alter query like below
if($RESULT){
$sqll="ALTER TABLE Your_table_Name ADD COLUMN Your_New_Column_Name varchar(20) NOT NULL DEFAULT 0";
}
SET #dbname = DATABASE();
SET #tablename = "table";
SET #columnname = "fieldname";
SET #preparedStatement = (SELECT IF(
(
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
(table_name = #tablename)
AND (table_schema = #dbname)
AND (column_name = #columnname)
) > 0,
"SELECT 1",
CONCAT("ALTER TABLE ", #tablename, " ADD ", #columnname, " DECIMAL(18,4) NULL;")
));
PREPARE alterIfNotExists FROM #preparedStatement;
EXECUTE alterIfNotExists;
DEALLOCATE PREPARE alterIfNotExists;
This below worked for me:
SELECT count(*)
INTO #exist
FROM information_schema.columns
WHERE table_schema = 'mydatabase'
and COLUMN_NAME = 'mycolumn'
AND table_name = 'mytable' LIMIT 1;
set #query = IF(#exist <= 0, 'ALTER TABLE mydatabase.`mytable` ADD COLUMN `mycolumn` MEDIUMTEXT NULL',
'select \'Column Exists\' status');
prepare stmt from #query;
EXECUTE stmt;
Sometimes it may happen that there are multiple schema created in a database.
So to be specific schema we need to target, so this will help to do it.
SELECT count(*) into #colCnt FROM information_schema.columns WHERE table_name = 'mytable' AND column_name = 'mycolumn' and table_schema = DATABASE();
IF #colCnt = 0 THEN
ALTER TABLE `mytable` ADD COLUMN `mycolumn` VARCHAR(20) DEFAULT NULL;
END IF;
Using this as an example:
https://dbabulletin.com/index.php/2018/03/29/best-practices-using-flyway-for-database-migrations/
DELIMITER $$
DROP PROCEDURE IF EXISTS upgrade_database_4_to_5 $$
CREATE PROCEDURE upgrade_database_4_to_5()
BEGIN
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
AND COLUMN_NAME='multi_user' AND TABLE_NAME='settings') ) THEN
ALTER TABLE `settings` ADD COLUMN `multi_user` TINYINT(1) NOT NULL DEFAULT 1;
END IF;
END $$
CALL upgrade_database_4_to_5() $$
DELIMITER ;
I was wondering if there's a way to check if an index exists before creating it or destroying it on MySQL. It appears that there was a feature request for this a few years back, but I can't find any documentation for a solution. This needs to be done in a PHP app using MDB2.
Here is my 4 liner:
set #exist := (select count(*) from information_schema.statistics where table_name = 'table' and index_name = 'index' and table_schema = database());
set #sqlstmt := if( #exist > 0, 'select ''INFO: Index already exists.''', 'create index i_index on tablename ( columnname )');
PREPARE stmt FROM #sqlstmt;
EXECUTE stmt;
IF EXISTS modifier is not built for DROP INDEX or CREATE INDEX yet. But you can check manually for the existence before creating/dropping an index.
Use this sentence to check whether the index already exists.
SHOW INDEX FROM table_name WHERE KEY_NAME = 'index_name'
If the query returns zero (0) then the index does not exists, then you can create it.
If the query returns a positive number, then the index exists, then you can drop it.
Here is a DROP INDEX IF EXISTS procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS drop_index_if_exists $$
CREATE PROCEDURE drop_index_if_exists(in theTable varchar(128), in theIndexName varchar(128) )
BEGIN
IF((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name =
theTable AND index_name = theIndexName) > 0) THEN
SET #s = CONCAT('DROP INDEX ' , theIndexName , ' ON ' , theTable);
PREPARE stmt FROM #s;
EXECUTE stmt;
END IF;
END $$
DELIMITER ;
This code was created based on the procedure from here: Determining if MySQL table index exists before creating
I tweaked answers found here and else where to come up with the following sprocs for dropping & creating indexes. Note that the AddTableIndex sproc can drop the index if need be. They also accept a schema name which was critical for my uses.
DELIMITER //
DROP PROCEDURE IF EXISTS migrate.DropTableIndex //
CREATE PROCEDURE migrate.DropTableIndex
(
in schemaName varchar(128) -- If null use name of current schema;
, in tableName varchar(128) -- If null an exception will be thrown.
, in indexName varchar(128) -- If null an exception will be thrown.
)
BEGIN
SET schemaName = coalesce(schemaName, schema());
IF((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = schemaName and table_name = tableName AND index_name = indexName) > 0) THEN
SET #s = CONCAT('DROP INDEX `' , indexName , '` ON `' , schemaName, '`.`', tableName, '`');
PREPARE stmt FROM #s;
EXECUTE stmt;
END IF;
END //
DROP PROCEDURE IF EXISTS migrate.AddTableIndex//
CREATE PROCEDURE migrate.AddTableIndex
(
IN schemaName varchar(128) -- If null use name of current schema;
, IN tableName varchar(128) -- If null an exception will be thrown.
, IN indexName varchar(128) -- If null an exception will be thrown.
, IN indexDefinition varchar(1024) -- E.g. '(expireTS_ ASC)'
, IN ifPresent ENUM('leaveUnchanged', 'dropAndReplace') -- null=leaveUnchanged.
, OUT outcome tinyint(1) -- 0=unchanged, 1=replaced, 4=added.
)
BEGIN
DECLARE doDrop tinyint(1) DEFAULT NULL;
DECLARE doAdd tinyint(1) DEFAULT NULL;
DECLARE tmpSql varchar(4096) DEFAULT '';
SET schemaName = coalesce(schemaName, schema());
SET ifPresent = coalesce(ifPresent, 'leaveUnchanged');
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = schemaName AND table_name = tableName AND index_name = indexName) THEN
IF (ifPresent = 'leaveUnchanged') THEN
SET doDrop = 0;
SET doAdd = 0;
SET outcome = 0;
ELSEIF (ifPresent = 'dropAndReplace')
THEN
SET doDrop = 1;
SET doAdd = 1;
SET outcome = 1;
END IF;
ELSE
SET doDrop = 0;
SET doAdd = 1;
SET outcome = 4;
END IF;
IF (doDrop = 1) THEN
SET tmpSql = concat( 'alter table `', schemaName, '`.`', tableName, '` drop index `', indexName, '` ');
SET #sql = tmpSql;
PREPARE tmp_stmt FROM #sql;
EXECUTE tmp_stmt;
DEALLOCATE PREPARE tmp_stmt;
END IF;
IF (doAdd = 1) THEN
SET tmpSql = concat( 'alter table `', schemaName, '`.`', tableName, '` add index `', indexName, '` (', indexDefinition, ')');
SET #sql = tmpSql;
PREPARE tmp_stmt FROM #sql;
EXECUTE tmp_stmt;
DEALLOCATE PREPARE tmp_stmt;
END IF;
END;
//
DELIMITER ;
I have something similar with using SELECT IF() statement in MySQL.
select if (
exists(
select distinct index_name from information_schema.statistics
where table_schema = 'schema_db_name'
and table_name = 'tab_name' and index_name like 'index_1'
)
,'select ''index index_1 exists'' _______;'
,'create index index_1 on tab_name(column_name_names)') into #a;
PREPARE stmt1 FROM #a;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
The advantage of using if() statement is that, it doesn’t need a stored procedures.
I think this will helpful to you drop your existing index.
DELIMITER //
CREATE PROCEDURE dropIndexing
()
BEGIN
IF EXISTS(
SELECT * FROM information_schema.statistics
WHERE TABLE_SCHEMA = DATABASE()
AND `table_name`='mytable'
AND `index_name` = 'myindex'
)
THEN
ALTER TABLE `mytable` DROP INDEX `myindex`;
END IF;
END //
DELIMITER ;
CALL dropIndexing();
DROP PROCEDURE dropIndexing;
MySQL Workbench version 6.3 (MySql fork MariaDb)
DROP INDEX IF EXISTS FK_customer__client_school__school_id ON dbname.tablename;
I was having problems with some of the solutions presented here. This is what I came up with:
DELIMITER $$
DROP PROCEDURE IF EXISTS myschema.create_index_if_not_exists $$
CREATE PROCEDURE myschema.create_index_if_not_exists(in p_tableName VARCHAR(128), in p_indexName VARCHAR(128), in p_columnName VARCHAR(128) )
BEGIN
PREPARE stmt FROM 'SELECT #indexCount := COUNT(1) from information_schema.statistics WHERE `table_name` = ? AND `index_name` = ?';
SET #table_name = p_tableName;
SET #index_name = p_indexName;
EXECUTE stmt USING #table_name, #index_name;
DEALLOCATE PREPARE stmt;
-- select #indexCount;
IF( #indexCount = 0 ) THEN
SELECT 'Creating index';
SET #createIndexStmt = CONCAT('CREATE INDEX ', p_indexName, ' ON ', p_tableName, ' ( ', p_columnName ,')');
PREPARE stmt FROM #createIndexStmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END $$
DELIMITER ;
Use it as follows:
call myschema.create_index_if_not_exists('MyTable','end_time_index','end_time');
This was tested on MAC OS X 10.8.2 with MySQL 5.5.24 and on Windows 7 with MySQL 5.5.21
Here is a workaround for the DROP INDEX IF EXISTS, that is missing in MySQL and MariaDB versions before v10.1.4. You can also use it for every other statement you want, that should be depend on the existence of an INDEX (e.g. for SELECT "info: index exists." like in the example below).
-- DROP INDEX IF EXISTS
SELECT
COUNT(*)
INTO
#INDEX_my_index_ON_TABLE_my_table_EXISTS
FROM
`information_schema`.`statistics`
WHERE
`table_schema` = 'my_database'
AND `index_name` = 'my_index'
AND `table_name` = 'my_table'
;
SET #statement := IF(
#INDEX_my_index_ON_TABLE_my_table_EXISTS > 0,
-- 'SELECT "info: index exists."',
'DROP INDEX `my_index` ON `my_table`',
'SELECT "info: index does not exist."'
);
PREPARE statement FROM #statement;
EXECUTE statement;
I want to alter my tables dynamically based on whether the table has specific column.
My database name is summer_cms, and there are over 50 tables in it.
What I want are below:
If a table has a column named add_time, then I would like to add a column add_user_id in it.
Similarly, I would like to add update_user_id in the table if update_time is found.
I know I should get it down in the process of creating the database schemas, but my database has been built and I have to alter it by need.
So I create a procedure to do it:
CREATE PROCEDURE ALTER_SUMMER_TABLE()
BEGIN
DECLARE tableName VARCHAR(64);
DECLARE exitence VARCHAR(64);
DECLARE ntable INT; # number of tables
DECLARE i INT; # index
SET i = 0;
# get the count of table
SELECT COUNT(DISTINCT(TABLE_NAME)) INTO ntable FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'summer_cms';
WHILE i < ntable DO
# select the specific table name into the variable of `tableName`.
SELECT TABLE_NAME INTO tableName
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND COLUMN_NAME = 'add_time'
LIMIT 1 OFFSET i;
# alter table, but I get error in this clause.
ALTER TABLE tableName ADD COLUMN `add_user_id` INT NOT NULL DEFAULT 0 COMMENT 'add user id';
# check if the table has `update_time`
SELECT TABLE_NAME INTO exitence
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND TABLE_NAME = tableName
AND COLUMN_NAME = 'update_time';
# add `update_user_id` if `update_time` be found.
IF exitence THEN
ALTER TABLE tableName ADD COLUMN `update_user_id` INT NOT NULL DEFAULT 0 COMMENT 'update user id';
END IF;
SET i = i + 1;
END WHILE;
END
But I got an error when I call this procedure.
Procedure execution failed
1146 - Table 'summer_cms.tableName' doesn't exist
Dose anyone could tell me what I was missing or wrong? Any help will be appreciated.
There a a few alterations you can make to your procedure to make it more streamlined as well as getting round a few problems.
First using a cursor to select the table names rather than using the two selects your using. Secondly to use a prepared statement to allow you to dynamically set the table name...
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `ALTER_SUMMER_TABLE`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE tableName VARCHAR(64);
declare cur cursor for SELECT TABLE_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND COLUMN_NAME = 'add_time';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
open cur;
start_loop: loop
fetch cur into tableName;
if (done = 1 )THEN
LEAVE start_loop;
END IF;
SET #sql = CONCAT('ALTER TABLE ', tableName,' ADD COLUMN `add_user_id` INT NOT NULL DEFAULT 0 ');
PREPARE stmt FROM #sql;
EXECUTE stmt;
end loop;
close cur;
END$$
DELIMITER ;
You could do a few tweaks - only fetch table names where the column doesn't already exist for example.
Here's an example of dynamic sql
drop procedure if exists alter_table;
delimiter //
CREATE DEFINER=`root`#`localhost` procedure alter_table()
begin
declare tablename varchar(20);
set tablename = 'u';
set #sqlstmt = concat('ALTER TABLE ', tableName, ' ADD COLUMN ', char(96), 'add_user_id', char(96), ' INT NOT NULL DEFAULT 0 COMMENT', char(39), 'add user id', char(39),';');
prepare stmt from #sqlstmt;
execute stmt;
deallocate prepare stmt;
end //
delimiter ;
Note I have used ascii backticks and single quotes.
I need to dynamically alter set of tables
Currently i can alter only one using below SP.
DROP PROCEDURE IF EXISTS add_version_to_actor;
DELIMITER $$
CREATE DEFINER=CURRENT_USER PROCEDURE add_version_to_actor (IN table_name VARCHAR(40) )
BEGIN
DECLARE colName TEXT;
SELECT column_name INTO colName
FROM information_schema.columns
WHERE table_schema = 'database_name'
AND table_name = table_name
AND column_name = 'column';
IF colName is null THEN
Alter Table database_name.table_name ADD `sequence` INT( 10 ) NOT NULL;
END IF;
END$$
DELIMITER ;
CALL add_version_to_actor('table1');
DROP PROCEDURE add_version_to_actor;
Currently 'table1' is a single parameter. I need to pass multiple table names as string like this CALL add_version_to_actor('table1','table2');and loop through all of them.How can this be achieved.
Thanks in advance.
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'email_subscription' AND COLUMN_NAME = 'subscribe_all')
THEN
ALTER TABLE email_subscription
ADD COLUMN subscribe_all TINYINT(1) DEFAULT 1,
ADD COLUMN subscribe_category varchar(512) DEFAULT NULL;
I had a look at huge amount of examples. but this query doesn't work, I got error of:
ERROR 1064 (42000): You have an error in your SQL syntax; check the
manual that corresponds to your MySQL server version for the right
syntax to use near 'IF NOT EXISTS (SELECT * FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =' at line 1
If your host doesn't give you permission to create or run procedures, I think I found another way to do this using PREPARE/EXECUTE and querying the schema:
SET #s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'table_name'
AND table_schema = DATABASE()
AND column_name = 'col_name'
) > 0,
"SELECT 1",
"ALTER TABLE table_name ADD col_name VARCHAR(100)"
));
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
you can create a procedure for the query,
DELIMITER $$
CREATE PROCEDURE Alter_Table()
BEGIN
DECLARE _count INT;
SET _count = ( SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'email_subscription' AND
COLUMN_NAME = 'subscribe_all');
IF _count = 0 THEN
ALTER TABLE email_subscription
ADD COLUMN subscribe_all TINYINT(1) DEFAULT 1,
ADD COLUMN subscribe_category varchar(512) DEFAULT NULL;
END IF;
END $$
DELIMITER ;
There is no equivalent syntax to achieve this in a single MySQL statement.
To get something simlilar, you can either
1) attempt to add the column with an ALTER TABLE, and let MySQL raise an error if a column of that name already exists in the table, or
2) query the information_schema.columns view to check if a column of that name exists in the table.
Note that you really do need to check for the table_schema, as well as the table_name:
SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'foo'
AND table_name = 'email_subscription'
AND column_name = 'subscribe_all'
and based on that, decide whether to run the ALTER TABLE
You are using MS SQL Server syntax in MySQL.
Also add condition for database name to check column existance.
Try this:
DELIMITER $$
CREATE PROCEDURE sp_AlterTable()
BEGIN
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbName' AND
TABLE_NAME = 'email_subscription' AND
COLUMN_NAME = 'subscribe_all') THEN
ALTER TABLE email_subscription
ADD COLUMN subscribe_all TINYINT(1) DEFAULT 1,
ADD COLUMN subscribe_category VARCHAR(512) DEFAULT NULL;
END IF;
END $$
DELIMITER ;
SET #s = (SELECT IF(
(SELECT COUNT(column_name)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'oc_bitcoin_wallets_receive'
AND table_schema = 'k_opencart2'
AND column_name = 'test3'
) > 0,
"SELECT 1",
"ALTER TABLE `oc_bitcoin_wallets_receive` ADD COLUMN `test3` INT NOT NULL AFTER `test2`;"
));
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Values for edit:
oc_bitcoin_wallets_receive - table name,
k_opencart2 - database name,
test3 - name of new column,
oc_bitcoin_wallets_receive - second location table
test3 - second location column,
test2 - name of column before new column.