agregar columna a la tabla mysql si no existe

Mi investigación y experimentos aún no han dado una respuesta, por lo que espero algo de ayuda.

Estoy modificando el archivo de instalación de una aplicación que en versiones anteriores no tenía una columna que quiera agregar ahora. No deseo agregar la columna manualmente, sino en el archivo de instalación y solo si la nueva columna no existe en la tabla.

La tabla se crea de la siguiente manera:

CREATE TABLE IF NOT EXISTS `#__comm_subscribers` ( `subscriber_id` int(11) NOT NULL auto_increment, `user_id` int(11) NOT NULL default '0', `subscriber_name` varchar(64) NOT NULL default '', `subscriber_surname` varchar(64) NOT NULL default '', `subscriber_email` varchar(64) NOT NULL default '', `confirmed` tinyint(1) NOT NULL default '0', `subscribe_date` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`subscriber_id`), UNIQUE KEY `subscriber_email` (`subscriber_email`) ) ENGINE=MyISAM CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' COMMENT='Subscribers for Comm are stored here.'; 

Si agrego lo siguiente, debajo de la statement create table, entonces no estoy seguro de lo que sucederá si la columna ya existe (y quizás esté poblada):

 ALTER TABLE `#__comm_subscribers` ADD `subscriber_surname`; ALTER TABLE `#__comm_subscribers` MODIFY `subscriber_surname` varchar(64) NOT NULL default ''; 

Entonces, probé lo siguiente que encontré en alguna parte. Esto no parece funcionar, pero no estoy del todo seguro de haberlo usado correctamente.

 /*delimiter '//' CREATE PROCEDURE addcol() BEGIN IF NOT EXISTS( SELECT * FROM information_schema.COLUMNS WHERE COLUMN_NAME='subscriber_surname' AND TABLE_NAME='#__comm_subscribers' ) THEN ALTER TABLE `#__comm_subscribers` ADD COLUMN `subscriber_surname` varchar(64) NOT NULL default ''; END IF; END; // delimiter ';' CALL addcol(); DROP PROCEDURE addcol;*/ 

¿Alguien tiene una buena manera de hacer esto?

Tenga en cuenta que INFORMATION_SCHEMA no es compatible con MySQL antes de 5.0. Tampoco se admiten los procedimientos almacenados antes de 5.0, por lo que si necesita admitir MySQL 4.1, esta solución no es buena.

Una solución utilizada por los marcos que usan migraciones de bases de datos es registrar en su base de datos un número de revisión para el esquema. Solo una tabla con una sola columna y una sola fila, con un número entero que indica qué revisión está vigente actualmente. Cuando actualice el esquema, incremente el número.

Otra solución sería probar el comando ALTER TABLE ADD COLUMN . Debería arrojar un error si la columna ya existe.

 ERROR 1060 (42S21): Duplicate column name 'newcolumnname' 

Capture el error y deséchelo en su script de actualización.

Aquí hay una solución de trabajo (simplemente probada con MySQL 5.0 en Solaris):

 DELIMITER $$ DROP PROCEDURE IF EXISTS upgrade_database_1_0_to_2_0 $$ CREATE PROCEDURE upgrade_database_1_0_to_2_0() BEGIN -- rename a table safely IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='my_old_table_name') ) THEN RENAME TABLE my_old_table_name TO my_new_table_name, END IF; -- add a column safely IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND COLUMN_NAME='my_additional_column' AND TABLE_NAME='my_table_name') ) THEN ALTER TABLE my_table_name ADD my_additional_column varchar(2048) NOT NULL DEFAULT ''; END IF; END $$ CALL upgrade_database_1_0_to_2_0() $$ DELIMITER ; 

A primera vista, probablemente se vea más complicado de lo que debería, pero tenemos que lidiar con los siguientes problemas aquí:

  • IF declaraciones IF solo funcionan en procedimientos almacenados, no cuando se ejecutan directamente, por ejemplo, en el cliente de MySQL
  • más elegante y conciso SHOW COLUMNS no funciona en el procedimiento almacenado, por lo que debe usar INFORMATION_SCHEMA
  • la syntax para delimitar sentencias es extraña en MySQL, por lo que debe redefinir el delimitador para poder crear procedimientos almacenados. ¡No olvides volver a cambiar el delimitador!
  • INFORMATION_SCHEMA es global para todas las bases de datos, no olvides filtrar en TABLE_SCHEMA=DATABASE() . DATABASE() devuelve el nombre de la base de datos seleccionada actualmente.

La mayoría de las respuestas abordan cómo agregar una columna de forma segura en un procedimiento almacenado, tuve la necesidad de agregar una columna a una tabla de manera segura sin usar un proceso almacenado y descubrí que MySQL no permite el uso de IF Exists() fuera de un SP . Publicaré mi solución que podría ayudar a alguien en la misma situación.

 SELECT count(*) INTO @exist FROM information_schema.columns WHERE table_schema = database() and COLUMN_NAME = 'original_data' AND table_name = 'mytable'; set @query = IF(@exist < = 0, 'alter table intent add column mycolumn4 varchar(2048) NULL after mycolumn3', 'select \'Column Exists\' status'); prepare stmt from @query; EXECUTE stmt; 

Si está en MariaDB, no necesita usar procedimientos almacenados. Solo use, por ejemplo:

 ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name tinyint(1) DEFAULT 0; 

Mira aquí

Otra forma de hacer esto sería ignorar el error con un declare continue handler :

 delimiter ;; create procedure foo () begin declare continue handler for 1060 begin end; alter table atable add subscriber_surname varchar(64); end;; call foo();; 

Creo que es más ordenado de esta manera que con una subconsulta exists . Especialmente si tiene muchas columnas para agregar y desea ejecutar el script varias veces.

se puede encontrar más información sobre los controladores de continuación en http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html

Estoy usando MySQL 5.5.19.

Me gusta tener scripts que pueda ejecutar y volver a ejecutar sin errores, especialmente cuando las advertencias parecen perdurar, apareciendo de nuevo más tarde mientras estoy ejecutando scripts que no tienen errores / advertencias. En cuanto a agregar campos, me escribí un procedimiento para hacerlo un poco menos tipeo:

 -- 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'); 

El código para crear el procedimiento addFieldIfNotExists es el siguiente:

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

No escribí un procedimiento para modificar una columna de forma segura, pero creo que el procedimiento anterior podría modificarse fácilmente para hacerlo.

Tomé el sproc del OP y lo hice reutilizable y el esquema independiente. Obviamente, todavía requiere MySQL 5.

 DROP PROCEDURE IF EXISTS AddCol; DELIMITER // CREATE PROCEDURE AddCol( IN param_schema VARCHAR(100), IN param_table_name VARCHAR(100), IN param_column VARCHAR(100), IN param_column_details VARCHAR(100) ) BEGIN IF NOT EXISTS( SELECT NULL FROM information_schema.COLUMNS WHERE COLUMN_NAME=param_column AND TABLE_NAME=param_table_name AND table_schema = param_schema ) THEN set @paramTable = param_table_name ; set @ParamColumn = param_column ; set @ParamSchema = param_schema; set @ParamColumnDetails = param_column_details; /* Create the full statement to execute */ set @StatementToExecute = concat('ALTER TABLE `',@ParamSchema,'`.`',@paramTable,'` ADD COLUMN `',@ParamColumn,'` ',@ParamColumnDetails); /* Prepare and execute the statement that was built */ prepare DynamicStatement from @StatementToExecute ; execute DynamicStatement ; /* Cleanup the prepared statement */ deallocate prepare DynamicStatement ; END IF; END // DELIMITER ; 

Acabo de probar el script del procedimiento almacenado. Parece que el problema son las ' marcas alrededor de los delimitadores. Los documentos MySQL muestran que los caracteres delimitadores no necesitan las comillas simples.

Entonces quieres:

 delimiter // 

En lugar de:

 delimiter '//' 

Funciona para mi 🙂

Si está ejecutando esto en un script, querrá agregar la siguiente línea para que vuelva a ejecutarse; de ​​lo contrario, obtendrá un error de procedimiento ya existente.

 drop procedure foo; 

La mejor forma de agregar la columna en PHP> PDO:

 $Add = $dbh->prepare("ALTER TABLE `YourCurrentTable` ADD `YourNewColumnName` INT NOT NULL"); $Add->execute(); 

Nota: la columna en la tabla no es repetible, eso significa que no necesitamos verificar la existencia de una columna, pero para resolver el problema, verificamos el código anterior:

por ejemplo, si funciona la alerta 1, si no es 0, lo que significa que la columna existe. 🙂

Verifique si existe columna o no en PDO (100%)

 { if(isset($_POST['Add'])) { $ColumnExist = $dbh->prepare("SELECT * FROM ColumnChecker where column_name='$insert_column_name' LIMIT 1"); $ColumnExist ->execute(); $ColumnName = $ColumnExist->fetch(2); $Display_Column_Name = $ColumnName['column_name']; if($Display_Column_Name == $insert_column_name) { echo "$Display_Column_Name already exist"; } //***************************** else { $InsertColumn = $dbh->prepare("insert into ColumnChecker ( column_name ) values ('$insert_column_name')"); $InsertColumn->execute(); if($InsertColumn) { $Add = $dbh->prepare("ALTER TABLE `$Table` ADD `$insert_column_name` $insert_column_type($insert_column_Length) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL "); $Add->execute(); if($Add) { echo 'Table has been updated'; } else { echo 'Sorry! Try again...'; } } } } }#Add Column into Table :) 
 $smpt = $pdo->prepare("SHOW fields FROM __TABLE__NAME__"); $smpt->execute(); $res = $smpt->fetchAll(PDO::FETCH_ASSOC); //print_r($res); 

Luego, en $ res por ciclo busque la clave de su columna Smth así:

  if($field['Field'] == '_my_col_'){ return true; } + **Below code is good for checking column existing in the WordPress tables:** public static function is_table_col_exists($table, $col) { global $wpdb; $fields = $wpdb->get_results("SHOW fields FROM {$table}", ARRAY_A); foreach ($fields as $field) { if ($field['Field'] == $col) { return TRUE; } } return FALSE; } 

El procedimiento de Jake https://stackoverflow.com/a/6476091/6751901 es una solución muy simple y buena para agregar nuevas columnas, pero con una línea adicional:

 DROP PROCEDURE IF EXISTS foo;; 

puede agregar nuevas columnas más adelante, y también funcionará la próxima vez:

 delimiter ;; DROP PROCEDURE IF EXISTS foo;; create procedure foo () begin declare continue handler for 1060 begin end; alter table atable add subscriber_surname varchar(64); alter table atable add subscriber_address varchar(254); end;; call foo();; 

A continuación se muestra el procedimiento almacenado en MySQL para agregar columna (s) en diferentes tablas en diferentes bases de datos si la columna no existe en una (s) tabla (s) de base de datos con las siguientes ventajas

  • se pueden agregar varias columnas a la vez para modificar varias tablas en diferentes bases de datos
  • se ejecutan tres comandos mysql, es decir, DROP, CREATE, CALL For Procedure
  • BASE DE DATOS El nombre debe ser cambios según USE, de lo contrario, puede haber problemas para múltiples datos
 DROP PROCEDURE IF EXISTS `AlterTables`; DELIMITER $$ CREATE PROCEDURE `AlterTables`() BEGIN DECLARE table1_column1_count INT; DECLARE table2_column2_count INT; SET table1_column1_count = ( SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'DATABASE_NAME' AND TABLE_NAME = 'TABLE_NAME1' AND COLUMN_NAME = 'TABLE_NAME1_COLUMN1'); SET table2_column2_count = ( SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'DATABASE_NAME' AND TABLE_NAME = 'TABLE_NAME2' AND COLUMN_NAME = 'TABLE_NAME2_COLUMN2'); IF table1_column1_count = 0 THEN ALTER TABLE `TABLE_NAME1`ADD `TABLE_NAME1_COLUMN1` text COLLATE 'latin1_swedish_ci' NULL AFTER `TABLE_NAME1_COLUMN3`,COMMENT='COMMENT HERE'; END IF; IF table2_column2_count = 0 THEN ALTER TABLE `TABLE_NAME2` ADD `TABLE_NAME2_COLUMN2` VARCHAR( 100 ) NULL DEFAULT NULL COMMENT 'COMMENT HERE'; END IF; END $$ DELIMITER ; call AlterTables(); 
 ALTER TABLE `subscriber_surname` ADD IF NOT EXISTS `#__comm_subscribers`.`subscriber_surname`; ALTER TABLE `#__comm_subscribers` MODIFY `subscriber_surname` varchar(64) NOT NULL default '';