160

I am trying to write a query that will check if a specific table in MySQL has a specific column, and if not — create it. Otherwise do nothing. This is really an easy procedure in any enterprise-class database, yet MySQL seems to be an exception.

I thought something like this would work, but it fails badly.

IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS 
           WHERE TABLE_NAME='prefix_topic' AND column_name='topic_last_update') 
BEGIN 
ALTER TABLE `prefix_topic` ADD `topic_last_update` DATETIME NOT NULL;
UPDATE `prefix_topic` SET `topic_last_update` = `topic_date_add`;
END;

Is there a way?

user2342558
  • 5,567
  • 5
  • 33
  • 54
clops
  • 5,085
  • 6
  • 39
  • 53
  • 1
    see this : http://www.cryer.co.uk/brian/mysql/howto_add_column_unless_exists.htm – Haim Evgi Aug 03 '10 at 10:58
  • Why not just create it? If it exists, the create will fail but you don't care. – Brian Hooper Aug 03 '10 at 10:59
  • the creation takes place inside a transaction and the failure will terminate the whole transaction, sad but true – clops Aug 03 '10 at 11:02
  • @haim — thans for the headups, but the query suggested in your link works inside a procedure only :( – clops Aug 03 '10 at 11:04
  • 2
    DDL statements cause implicit commit in current transaction. http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html – Mchl Aug 03 '10 at 11:06

13 Answers13

335

This works well for me.

SHOW COLUMNS FROM `table` LIKE 'fieldname';

With PHP it would be something like...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;
Martin Braun
  • 10,906
  • 9
  • 64
  • 105
Mfoo
  • 3,615
  • 1
  • 16
  • 11
  • 69
    You answer the question + some info that helped me and probably others, +1 – Francisco Presencia Nov 22 '12 at 22:38
  • 1
    @Mfoo Thanks Mfoo, you saved my day! Works like charm. One of the best solutions apart from creating Procedures for this task. – webblover Feb 14 '14 at 17:49
  • 10
    Yura: The pure SQL / MySQL answer is the first part where he says use "SHOW COLUMNS FROM table LIKE 'fieldname'". You can disregard the PHP code, that's just an example of one way to retrieve and interpret the result if you happen to be using PHP. – orrd Mar 25 '14 at 19:05
  • Cannot find stored procedure `SHOW` – codenamezero Jul 26 '17 at 14:23
  • 1
    @codenamezero I assume you are referring to using MSSQL, this question was regarding MySQL. refer to [this post](https://stackoverflow.com/questions/38133960/sql-server-could-not-find-stored-procedure-show) for MSSQL – Mfoo Jul 27 '17 at 18:03
  • I needed to do it in PHP, you saved me some effort. I'm using that effort to write this comment. Thanks! – CttCJim Mar 16 '23 at 18:43
  • Good answer, just needs the $ signs for the PHP variables: $result = mysql_query("SHOW COLUMNS FROM `$table` LIKE '$fieldname'"); – Skyfish Jul 13 '23 at 10:40
178

@julio

Thanks for the SQL example. I tried the query and I think it needs a small alteration to get it working properly.

SELECT * 
FROM information_schema.COLUMNS 
WHERE 
    TABLE_SCHEMA = 'db_name' 
AND TABLE_NAME = 'table_name' 
AND COLUMN_NAME = 'column_name'

That worked for me.

Thanks!

forsvarir
  • 10,749
  • 6
  • 46
  • 77
Iain
  • 2,137
  • 1
  • 13
  • 5
  • It appears from my limited research that not all hosting environments have an information_schema DB. All the cpanel environments I have used have it. This provided solution depends on this DB existing. – cardi777 Mar 10 '14 at 01:26
  • 3
    This answer is better than using "SHOW COLUMNS" because it uses the ANSI standard way to get table information, unlike SHOW COLUMNS which is specific to MySQL. So this solution will work with other databases. Using "information_schema" sounds odd and you would think it wouldn't be the standard SQL way to do this, but it is. – orrd Mar 25 '14 at 19:46
  • 5
    Note that this answer only gets you the information about the existence of the column. If you want to conditionally-execute some DDL statements, you'll have to wrap the whole thing in a procedure which allows statements like `IF`, etc. See http://stackoverflow.com/questions/7384711/if-conditional-in-sql-script-for-mysql for an example of how to wrap a procedure around the test for the column and the conditional DML statement. – Christopher Schultz Jul 23 '14 at 20:14
  • @Iain : http://stackoverflow.com/questions/32962149/mysql-multiple-database-check-column-exist-if-not-add-column/32962415?noredirect=1#comment53762396_32962415 I have refered your answer – Amar Singh Oct 06 '15 at 11:42
  • This is nicer than the "SHOW COLUMNS" approach below as can be used in parameterized queries reducing the risk of SQL injection. Just wanted to add you can use the DATABASE() function to populate the TABLE_SCHEMA column. – Andrew Jul 16 '18 at 10:08
22

Just to help anyone who is looking for a concrete example of what @Mchl was describing, try something like

 SELECT * FROM information_schema.COLUMNS 
 WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' 
 AND COLUMN_NAME = 'my_column'`

If it returns false (zero results) then you know the column doesn't exist.

Martin
  • 22,212
  • 11
  • 70
  • 132
julio
  • 6,630
  • 15
  • 60
  • 82
  • 2
    I believe it should be `TABLE_NAME = 'my_table'`, TABLE_SCHEMA is the schema the table is in. I.e. `SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'` – AaronHolland Nov 06 '19 at 23:34
11

I threw this stored procedure together with a start from @lain's comments above, kind of nice if you need to call it more than a few times (and not needing php):

delimiter //
-- ------------------------------------------------------------
-- Use the inforamtion_schema to tell if a field exists.
-- Optional param dbName, defaults to current database
-- ------------------------------------------------------------
CREATE PROCEDURE fieldExists (
OUT _exists BOOLEAN,      -- return value
IN tableName CHAR(255),   -- name of table to look for
IN columnName CHAR(255),  -- name of column to look for
IN dbName CHAR(255)       -- optional specific db
) BEGIN
-- try to lookup db if none provided
SET @_dbName := IF(dbName IS NULL, database(), dbName);

IF CHAR_LENGTH(@_dbName) = 0
THEN -- no specific or current db to check against
  SELECT FALSE INTO _exists;
ELSE -- we have a db to work with
  SELECT IF(count(*) > 0, TRUE, FALSE) INTO _exists
  FROM information_schema.COLUMNS c
  WHERE 
  c.TABLE_SCHEMA    = @_dbName
  AND c.TABLE_NAME  = tableName
  AND c.COLUMN_NAME = columnName;
END IF;
END //
delimiter ;

Working with fieldExists

mysql> call fieldExists(@_exists, 'jos_vm_product', 'child_option', NULL) //
Query OK, 0 rows affected (0.01 sec)

mysql> select @_exists //
+----------+
| @_exists |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> call fieldExists(@_exists, 'jos_vm_product', 'child_options', 'etrophies') //
Query OK, 0 rows affected (0.01 sec)

mysql> select @_exists //
+----------+
| @_exists |
+----------+
|        1 |
+----------+
quickshiftin
  • 66,362
  • 10
  • 68
  • 89
10

Following is another way of doing it using plain PHP without the information_schema database:

$chkcol = mysql_query("SELECT * FROM `my_table_name` LIMIT 1");
$mycol = mysql_fetch_array($chkcol);
if(!isset($mycol['my_new_column']))
  mysql_query("ALTER TABLE `my_table_name` ADD `my_new_column` BOOL NOT NULL DEFAULT '0'");
wvasconcelos
  • 157
  • 1
  • 3
  • Why would you want to avoid using information_schema? It is exists just for this purpose. (Also, this thread is quite old and was already answered.) – Leigh Apr 07 '12 at 04:07
  • 1
    In my tests, this is about 10-50x faster than using information_schema. It does require that the table have atleast one row, which you can't always guarantee. – Martijn Jan 28 '13 at 10:07
  • `isset()` would trow 'false' if the array key exists but the value is **NULL**. It's better to use `array_key_exists()` like `if( !array_key_exists( 'my_new_column', $mycol ) )` – Paul Geisler Jan 20 '16 at 08:47
  • 1
    This answer made me facepalm because I overlooked a simple `isset()` check. It doesn't solve the question, but it is better if you already need to execute the select query and have the result in memory. – Siphon Aug 03 '16 at 13:47
8

Select just column_name from information schema and put the result of this query into variable. Then test the variable to decide if table needs alteration or not.

P.S. Don't foget to specify TABLE_SCHEMA for COLUMNS table as well.

Mchl
  • 61,444
  • 9
  • 118
  • 120
2

I am using this simple script:

mysql_query("select $column from $table") or mysql_query("alter table $table add $column varchar (20)");

It works if you are already connected to the database.

vio
  • 29
  • 2
  • This would only work if the table also happened to also have rows of data in it. But if the table was empty, this wouldn't work. – orrd Mar 25 '14 at 19:08
  • 1
    not perfect, uses old drivers, doesn't work if the table is empty, inputs not escaped, but I like how you did it in one line. +1 – I wrestled a bear once. Jan 05 '15 at 21:06
2

This work for me with sample PDO :

public function GetTableColumn() {      
$query  = $this->db->prepare("SHOW COLUMNS FROM `what_table` LIKE 'what_column'");  
try{            
    $query->execute();                                          
    if($query->fetchColumn()) { return 1; }else{ return 0; }
    }catch(PDOException $e){die($e->getMessage());}     
}
user3706926
  • 181
  • 2
  • 12
1

DO NOT put ALTER TABLE/MODIFY COLS or any other such table mod operations inside a TRANSACTION. Transactions are for being able to roll back a QUERY failure not for ALTERations...it will error out every time in a transaction.

Just run a SELECT * query on the table and check if the column is there...

gmize
  • 89
  • 1
  • `ALTER` (and DDL like that) in MySQL indeed commit (implicitly) the transaction. But using SELECT * would generate a big overhead in network for just checking the existance of the column. You might instead try `SELECT my_col_to_check FROM t LIMIT 0`: if mysql generates an error, then column probably doesn't exist (still, check the error, as it might be a network issue or whatever!); if it generates no error, then column exists. I'm not sure it's the best way to check for column existance. – Xenos Oct 10 '19 at 16:29
1

Many thanks to Mfoo who has put the really nice script for adding columns dynamically if not exists in the table. I have improved his answer with PHP. The script additionally helps you find how many tables actually needed 'Add column' mysql comand. Just taste the recipe. Works like charm.

<?php
ini_set('max_execution_time', 0);

$host = 'localhost';
$username = 'root';
$password = '';
$database = 'books';

$con = mysqli_connect($host, $username, $password);
if(!$con) { echo "Cannot connect to the database ";die();}
mysqli_select_db($con, $database);
$result=mysqli_query($con, 'show tables');
$tableArray = array();
while($tables = mysqli_fetch_row($result)) 
{
     $tableArray[] = $tables[0];    
}

$already = 0;
$new = 0;
for($rs = 0; $rs < count($tableArray); $rs++)
{
    $exists = FALSE;

    $result = mysqli_query($con, "SHOW COLUMNS FROM ".$tableArray[$rs]." LIKE 'tags'");
    $exists = (mysqli_num_rows($result))?TRUE:FALSE;

    if($exists == FALSE)
    {
        mysqli_query($con, "ALTER TABLE ".$tableArray[$rs]." ADD COLUMN tags VARCHAR(500) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL");
        ++$new;
        echo '#'.$new.' Table DONE!<br/>';
    }
    else
    {
        ++$already;
        echo '#'.$already.' Field defined alrady!<br/>';    
    }
    echo '<br/>';
}
?>
webblover
  • 1,196
  • 2
  • 12
  • 30
1

There are two functions below the first one let you check if a column in a database table exists which requires two arguments. Table name and column name.

function if_column_exists( $table, $column ) {
    global $db;
    
    if ( empty ( $table ) || empty ( $column ) ) {
        return FALSE;
    }
    if ( $result = $db->query( "SHOW COLUMNS FROM $table LIKE '$column'" ) ) {
        if ( $result->num_rows == 0 ) {
            return FALSE;
        } else {
            return TRUE;
        }
    }
}

To use the above function you have to call it by passing table name and column name like below.

if (  if_column_exists( 'accounts', 'group_id' ) == FALSE ) {
    $query  = "ALTER TABLE `accounts` ADD `group_id` bigint(20) NULL AFTER `memo`";
    $result = $db->query($query) or die($db->error);
}

The next function helps you to identify if a table exists or not and accepts the argument table name only.

function if_table_exists( $tablename ) {
    global $db; 

    if ( empty( $tablename ) ) {
        return FALSE;
    }
    if($result = $db->query("SHOW TABLES LIKE '$tablename'")) {
        if($result->num_rows == 0) {
            return FALSE;
        } else {
            return TRUE;
        }
    }
}

To call it use the following method with single table name argument.

if ( if_table_exists("messages") == FALSE ) { 
    $query = 'CREATE TABLE `messages` (
        `message_id` bigint(20) NOT NULL AUTO_INCREMENT,
        `message_datetime` datetime NOT NULL,
        `message_detail` varchar(1000) NULL,
        PRIMARY KEY (`message_id`)
    )'; 
    $result = $db->query($query) or die($db->error);
    echo 'Messages Table created.<br>';
}

Please note that you are passing global object of database as $db in the function so make sure its replaced with your database object or as below.

define ("DB_HOST", "localhost"); //Databse Host.
    define ("DB_USER", "root"); //Databse User.
    define ("DB_PASS", ""); //database password.
    define ("DB_NAME", "general_ledger"); //database Name.

    $db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);

    if($db->connect_errno > 0){
        die('Unable to connect to database [' . $db->connect_error . ']');
    }
0

Suggestions use COUNT(*) in place of *

SELECT
    COUNT(*) AS column_count
FROM
    information_schema.COLUMNS
WHERE
    TABLE_SCHEMA = '$schema_name' AND
    TABLE_NAME = '$table_name' AND
    COLUMN_NAME = '$column_name'
Rich R
  • 367
  • 4
  • 15
0

Updated version of mfoo's answer for PHP7+

/* Check if a table contains a given field. */
function ColumnExists($conn, $table, $fieldname)
{
    $result = mysqli_query($conn, "SHOW COLUMNS FROM `$table` LIKE '$fieldname'");
    $exists = (mysqli_num_rows($result))?TRUE:FALSE;
    return $exists;
}
Skyfish
  • 119
  • 2
  • 4