22

Is there a way to check if a column exists in a mySQL DB prior to (or as) the ALTER TABLE ADD coumn_name statement runs? Sort of an IF column DOES NOT EXIST ALTER TABLE thing.

I've tried ALTER IGNORE TABLE my_table ADD my_column but this still throws the error if the column I'm adding already exists.

EDIT: use case is to upgrade a table in an already installed web app-- so to keep things simple, I want to make sure the columns I need exist, and if they don't, add them using ALTER TABLE

julio
  • 6,630
  • 15
  • 60
  • 82
  • Have you tried checking the [syntax description](http://dev.mysql.com/doc/refman/5.1/en/alter-table.html) of the alter table statement? This stuff is documented, you know? – GolezTrol Nov 21 '11 at 22:57
  • 1
    Isn't it a bit worrying that you're running DDL changes on your tables without knowing their structure? What's the use case? – Russell Nov 21 '11 at 22:57
  • 2
    @GolezTrol-- yes, clearly I did read the docs, but I'm getting an error even when using the IGNORE as documented in the page you referenced-- so I'm asking how to issue the alter table only when the column doesn't exist. Is that unclear? – julio Nov 21 '11 at 23:03
  • 1
    @Russell One use case is rollback scripts. If the forward script fails for whatever reason, the rollback script might try to roll back changes that weren't ever executed in the first place. So the check allows the rollback script to decide for any given reversion whether to do it. –  Feb 26 '14 at 07:43
  • 2
    @julio, never too late to mark an answer accepted and pass a welcome bit of SO karma along to someone who tried to help you out – Anne Gunn Sep 28 '16 at 17:59

10 Answers10

10

Since mysql control statements (e.g. "IF") only work in stored procedures, a temporary one can be created and executed:

DROP PROCEDURE IF EXISTS add_version_to_actor;

DELIMITER $$

CREATE DEFINER=CURRENT_USER PROCEDURE add_version_to_actor ( ) 
BEGIN
DECLARE colName TEXT;
SELECT column_name INTO colName
FROM information_schema.columns 
WHERE table_schema = 'connjur'
    AND table_name = 'actor'
AND column_name = 'version';

IF colName is null THEN 
    ALTER TABLE  actor ADD  version TINYINT NOT NULL DEFAULT  '1' COMMENT  'code version of actor when stored';
END IF; 
END$$

DELIMITER ;

CALL add_version_to_actor;

DROP PROCEDURE add_version_to_actor;
j.raymond
  • 1,845
  • 1
  • 15
  • 15
gerardw
  • 5,822
  • 46
  • 39
8

Utility functions and procedures

First, I have a set of utility functions and procedures that I use to do things like drop foreign keys, normal keys and columns. I just leave them in the database so I can use them as needed.

Here they are.

delimiter $$

create function column_exists(ptable text, pcolumn text)
  returns bool
  reads sql data
begin
  declare result bool;
  select
    count(*)
  into
    result
  from
    information_schema.columns
  where
    `table_schema` = 'my_database' and
    `table_name` = ptable and
    `column_name` = pcolumn;
  return result;
end $$

create function constraint_exists(ptable text, pconstraint text)
  returns bool
  reads sql data
begin
  declare result bool;
  select
    count(*)
  into
    result
  from
    information_schema.table_constraints
  where
    `constraint_schema` = 'my_database' and
    `table_schema` = 'my_database' and
    `table_name` = ptable and
    `constraint_name` = pconstraint;
  return result;
end $$

create procedure drop_fk_if_exists(ptable text, pconstraint text)
begin
  if constraint_exists(ptable, pconstraint) then
    set @stat = concat('alter table ', ptable, ' drop foreign key ', pconstraint);
    prepare pstat from @stat;
    execute pstat;
  end if;
end $$

create procedure drop_key_if_exists(ptable text, pconstraint text)
begin
  if constraint_exists(ptable, pconstraint) then
    set @stat = concat('alter table ', ptable, ' drop key ', pconstraint);
    prepare pstat from @stat;
    execute pstat;
  end if;
end $$

create procedure drop_column_if_exists(ptable text, pcolumn text)
begin
  if column_exists(ptable, pcolumn) then
    set @stat = concat('alter table ', ptable, ' drop column ', pcolumn);
    prepare pstat from @stat;
    execute pstat;
  end if;
end $$

delimiter ;

Dropping constraints and columns using the utilities above

With those in place, it is pretty easy to use them to check columns and constraints for existence:

-- Drop service.component_id
call drop_fk_if_exists('service', 'fk_service_1');
call drop_key_if_exists('service', 'component_id');
call drop_column_if_exists('service', 'component_id');

-- Drop commit.component_id
call drop_fk_if_exists('commit', 'commit_ibfk_1');
call drop_key_if_exists('commit', 'commit_idx1');
call drop_column_if_exists('commit', 'component_id');

-- Drop component.application_id
call drop_fk_if_exists('component', 'fk_component_1');
call drop_key_if_exists('component', 'application_id');
call drop_column_if_exists('component', 'application_id');
  • Works on MySQL. BEST ANSWER EVER! If you run a schema and you keep getting errors while fine tuning this answer to your needs, you may need to use DROP statements. After testing, you may remove them. Example (first two lines, then answer's code): DROP function IF EXISTS column_exists; DROP procedure IF EXISTS rename_column_if_exists; – Juliano Suman Curti Jul 05 '23 at 17:12
8

Do you think you can try this?:

SELECT IFNULL(column_name, '') INTO @colName
FROM information_schema.columns 
WHERE table_name = 'my_table'
AND column_name = 'my_column';

IF @colName = '' THEN 
    -- ALTER COMMAND GOES HERE --
END IF;

It's no one-liner, but can you at least see if it will work for you? At least while waiting for a better solution..

Nonym
  • 6,199
  • 1
  • 25
  • 21
  • I get a `Unknown column 'column_name' in 'field list'` error if the column doesn't exist... – bafromca Aug 27 '14 at 15:58
  • 1
    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 @colName = '' THEN ALTER TABLE vegetables ADD vegetable_color VARCHAR(25' at line 1 – AquaAlex May 08 '18 at 03:11
5

Make a count sentence with the example below by John Watson.

 SELECT count(*) FROM information_schema.COLUMNS
     WHERE COLUMN_NAME = '...'
     and TABLE_NAME = '...'
     and TABLE_SCHEMA = '...'

Save that result in an integer and then make it a condition to apply the ADD COLUMN sentence.

mjk
  • 2,443
  • 4
  • 33
  • 33
Duvan Barros
  • 51
  • 1
  • 1
  • 2
    Can you elaborate on how you'd save the result and make it a condition for application of ADD COLUMN? – mjk Sep 19 '13 at 17:39
1

Although its quite an old post but still i feel good about sharing my solution to this issue. If column doesn't exist then an exception would occur definitely and then i am creating the column in table.

I just used the code below:

 try
   {
         DATABASE_QUERY="SELECT gender from USER;";
         db.rawQuery(DATABASE_QUERY, null);
   }
   catch (Exception e)
   {
    e.printStackTrace();

        DATABASE_UPGRADE="alter table USER ADD COLUMN gender VARCHAR(10) DEFAULT 0;";
                db.execSQL(DATABASE_UPGRADE);
   } 
Wahib Ul Haq
  • 4,185
  • 3
  • 44
  • 41
  • In case the are a huge number of gender entries in USER it might be good to limit the search to one item so it is faster, that is SELECT gender from user limit 1; – Keir May 13 '19 at 22:54
1

You can test if a column exists with:

IF EXISTS (
     SELECT * FROM information_schema.COLUMNS
     WHERE COLUMN_NAME = '...'
     and TABLE_NAME = '...'
     and TABLE_SCHEMA = '...')

...

Just fill in your column name, table name, and database name.

John Watson
  • 2,554
  • 1
  • 17
  • 13
  • 4
    this is giving me a `#1064 - 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 EXISTS ( SELECT * FROM information_schema.COLUMNS WHERE COLUMN_NAME'` – julio Nov 22 '11 at 00:06
  • 2
    IF can only be used inside a procedure, trigger etc. – Ryan Williams Oct 23 '14 at 05:01
0

You can create a procedure with a CONTINUE handler in case the column exists (please note this code doesn't work in PHPMyAdmin):

DROP PROCEDURE IF EXISTS foo;
CREATE PROCEDURE foo() BEGIN
    DECLARE CONTINUE HANDLER FOR 1060 BEGIN END;
    ALTER TABLE `tableName` ADD `columnName` int(10) NULL AFTER `otherColumn`;
END;
CALL foo();
DROP PROCEDURE foo;

This code should not raise any error in case the column already exists. It will just do nothing and carry on executing the rest of the SQL.

OMA
  • 3,442
  • 2
  • 32
  • 39
0
DELIMITER $$

DROP PROCEDURE IF EXISTS `addcol` $$
CREATE DEFINER=`admin`@`localhost` PROCEDURE `addcol`(tbn varchar(45), cn varchar(45), ct varchar(45))
BEGIN
#tbn: table name, cn: column name, ct: column type
DECLARE CONTINUE HANDLER FOR 1060 BEGIN END;
set cn = REPLACE(cn, ' ','_');
set @a = '';
set @a = CONCAT("ALTER TABLE `", tbn ,"` ADD column `", cn ,"` ", ct);
PREPARE stmt FROM @a;
EXECUTE stmt;

END $$

DELIMITER ;
0

This syntax work for me :

SHOW COLUMNS FROM < tablename > LIKE '< columnName >'

More in this post : https://mzulkamal.com/blog/mysql-5-7-check-if-column-exist?viewmode=0

shamcs
  • 629
  • 6
  • 15
-3

As per MYSQL Community:

IGNORE is a MySQL extension to standard SQL. It controls how ALTER TABLE works if there are duplicates on unique keys in the new table or if warnings occur when strict mode is enabled. If IGNORE is not specified, the copy is aborted and rolled back if duplicate-key errors occur. If IGNORE is specified, only one row is used of rows with duplicates on a unique key. The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.

So a working Code is: ALTER IGNORE TABLE CLIENTS ADD CLIENT_NOTES TEXT DEFAULT NULL;

Data posted here: http://dev.mysql.com/doc/refman/5.1/en/alter-table.html

JackSparrow
  • 948
  • 1
  • 11
  • 9
  • Sorry man but IGNORE doesn't do this thing. It checks only for duplicates in unique keys, nothing more. – bksi Mar 10 '15 at 00:06
  • Hi bksi, I hope you checked the MySQL Developer community regarding this post before adding your suggestion to this as I gave the link of it. And if you are right and MySQL community are wrong, please also suggest them to cross check their forum and get help from you. – JackSparrow Mar 16 '15 at 16:24
  • Did you test your solution? Because i tested it and it doesn't work. When you have a column antd try alter it to add same column with ignore, same error will occurs. – bksi Mar 17 '15 at 11:35