Sunday, October 21, 2012

MySQL ALTER TABLE ADD COLUMN IF NOT EXISTS

I wrote a MySQL function and procedure that will add a database column unless it exists already. The following code would add 3 fields to the template table, unless they already exist:

-- add fields to template table to support ignoring extra data 
-- at the top/bottom of every page

CALL addFieldIfNotExists ('template', 'firstPageHeaderEndY', 'INT NOT NULL DEFAULT 0');
CALL addFieldIfNotExists ('template', 'pageHeaderEndY', 'INT NOT NULL DEFAULT 0');
CALL addFieldIfNotExists ('template', 'pageFooterBeginY', 'INT NOT NULL DEFAULT 792');

Here is the actual code for the above procedure:

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

    -- http://javajon.blogspot.com/2012/10/mysql-alter-table-add-column-if-not.html

    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;
$$

4 comments:

  1. Good code. It has been very useful :-)

    ReplyDelete
  2. Should you end the script with DELIMITER ; ?
    I would like to run a script on software update, that should add a column, if it doesn't exist. So i'm running an SQL script that starts with your procedure declaration, then i'm adding: DELIMITER ;
    and then i'm doing the procedure call.
    Haven't tried it yet, hope it works

    ReplyDelete
    Replies
    1. Yes, you are correct. If you want to run additional scripts following the create procedure scripts above, it would be wise to follow up with DELIMITER ;

      Delete