MySQL, compruebe si existe una columna en una tabla con SQL

130

Estoy tratando de escribir una consulta que verifique si una tabla específica en MySQL tiene una columna específica, y si no, créala. De lo contrario no hagas nada. Este es realmente un procedimiento fácil en cualquier base de datos de clase empresarial, pero MySQL parece ser una excepción.

Pensé algo como

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;

funcionaría, pero falla mucho. ¿Hay alguna manera?

clops
fuente
¿Por qué no solo crearlo? Si existe, la creación fallará pero no le importa.
Brian Hooper el
la creación se lleva a cabo dentro de una transacción y la falla terminará toda la transacción, triste pero cierto
clops
@haim: gracias por los headups, pero la consulta sugerida en su enlace funciona solo dentro de un procedimiento :(
clops
2
Las declaraciones DDL causan confirmación implícita en la transacción actual. dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
MCHL

Respuestas:

259

Esto funciona bien para mi.

SHOW COLUMNS FROM `table` LIKE 'fieldname';

Con PHP sería algo así como ...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;
Mfoo
fuente
8
La pregunta no es cómo hacer eso usando php + sql o java + sql, es cómo hacerlo usando sql / mysql puro, de ahí el voto negativo
Yuriy Nakonechnyy
61
Respondes la pregunta + alguna información que me ayudó y probablemente a otros, +1
Francisco Presencia
@ Mfoo Gracias Mfoo, ¡me salvaste el día! Funciona como encanto. Una de las mejores soluciones además de crear procedimientos para esta tarea.
webblover
8
Yura: La respuesta pura de SQL / MySQL es la primera parte donde dice que use "MOSTRAR COLUMNAS DE LA TABLA COMO 'nombre de campo'". Puede ignorar el código PHP, ese es solo un ejemplo de una forma de recuperar e interpretar el resultado si está usando PHP.
orden
1
@codenamezero Supongo que se refiere al uso de MSSQL, esta pregunta se refería a MySQL. consulte esta publicación para MSSQL
Mfoo
158

@julio

Gracias por el ejemplo de SQL. Intenté la consulta y creo que necesita una pequeña modificación para que funcione correctamente.

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

Eso funcionó para mí.

¡Gracias!

Iain
fuente
De mi investigación limitada parece que no todos los entornos de alojamiento tienen un DB de información_esquema. Todos los entornos cpanel que he usado lo tienen. Esta solución proporcionada depende de esta base de datos existente.
cardi777
2
Esta respuesta es mejor que usar "MOSTRAR COLUMNAS" porque usa la forma estándar ANSI para obtener información de la tabla, a diferencia de MOSTRAR COLUMNAS que es específico de MySQL. Entonces, esta solución funcionará con otras bases de datos. Usar "information_schema" suena extraño y pensarías que no sería la forma estándar de SQL para hacerlo, pero lo es.
orden
55
Tenga en cuenta que esta respuesta solo le brinda la información sobre la existencia de la columna. Si desea ejecutar condicionalmente algunas instrucciones DDL, tendrá que ajustar todo en un procedimiento que permita declaraciones como IF, etc. Consulte stackoverflow.com/questions/7384711/... para ver un ejemplo de cómo envolver un procedimiento. la prueba para la columna y la declaración condicional DML.
Christopher Schultz
@Iain: stackoverflow.com/questions/32962149/… He referido su respuesta
Amar Singh
Esto es mejor que el siguiente enfoque "MOSTRAR COLUMNAS", ya que puede usarse en consultas parametrizadas que reducen el riesgo de inyección de SQL. Solo quería agregar que puede usar la función DATABASE () para completar la columna TABLE_SCHEMA.
Andrew
16

Solo para ayudar a cualquiera que esté buscando un ejemplo concreto de lo que @Mchl estaba describiendo, intente algo como

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

Si devuelve falso (cero resultados), entonces sabe que la columna no existe.

julio
fuente
2
Creo que debería ser TABLE_NAME = 'my_table', TABLE_SCHEMA es el esquema en el que se encuentra la tabla. Es decirSELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'
AaronHolland, el
10

La siguiente es otra forma de hacerlo usando PHP simple sin la base de datos information_schema:

$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
fuente
¿Por qué querrías evitar usar información_esquema? Existe solo para este propósito. (Además, este hilo es bastante antiguo y ya fue respondido.)
Leigh
1
En mis pruebas, esto es aproximadamente 10-50 veces más rápido que usar information_schema. Requiere que la tabla tenga al menos una fila, lo que no siempre puede garantizar.
Martijn
isset()trow 'false' si la clave de matriz existe pero el valor es NULL . Es mejor usar array_key_exists()comoif( !array_key_exists( 'my_new_column', $mycol ) )
Paul Geisler
1
Esta respuesta me dejó con la cara abierta porque pasé por alto un simple isset()cheque. No resuelve la pregunta, pero es mejor si ya necesita ejecutar la consulta de selección y tener el resultado en la memoria.
Syphon
10

Lancé este procedimiento almacenado junto con un comienzo de los comentarios de @ lain anteriores, algo bueno si necesita llamarlo más de unas pocas veces (y no necesita 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 ;

Trabajando con 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
fuente
Mister @quickshiftin, muchas gracias. Esto me ayuda a verificar si una tabla es expirable , verificando si tiene un ExpirationDatecampo. 😊
Jeancarlo Fontalvo
@JeancarloFontalvo ¡Un placer! También revisé mi proyecto mysql-inspectors que comencé para inspeccionar el esquema con métodos de nivel superior.
quickshiftin
1
OMG Es como una biblioteca 😱. Gracias por compartirlo señor!
Jeancarlo Fontalvo
8

Seleccione solo column_name del esquema de información y ponga el resultado de esta consulta en variable. Luego pruebe la variable para decidir si la tabla necesita ser alterada o no.

PD: No olvide especificar también TABLE_SCHEMA para la tabla COLUMNS.

Mchl
fuente
1
Soy bastante nuevo en MySQL, ¿podrías publicar un pequeño ejemplo aquí?
clops
2

Estoy usando este script simple:

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

Funciona si ya está conectado a la base de datos.

vio
fuente
Esto solo funcionaría si la tabla también tuviera filas de datos. Pero si la mesa estuviera vacía, esto no funcionaría.
orden
1
no es perfecto, usa controladores antiguos, no funciona si la tabla está vacía, no se escapan las entradas, pero me gusta cómo lo hizo en una línea. +1
Luché con un oso una vez.
1

Muchas gracias a Mfoo, que ha puesto el script realmente agradable para agregar columnas dinámicamente si no existe en la tabla. He mejorado su respuesta con PHP . El script además lo ayuda a encontrar cuántas tablas realmente necesitaban 'Agregar columna' mysql comand. Solo prueba la receta. Funciona como encanto.

<?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
fuente
1

Este trabajo para mí con muestra 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());}     
}
usuario3706926
fuente
0

NO coloque ALTER TABLE / MODIFY COLS ni ninguna otra operación de mod de tabla dentro de una TRANSACTION. Las transacciones son para poder revertir un error de CONSULTA, no para ALTERACIONES ... se producirá un error cada vez que se realice una transacción.

Simplemente ejecute una consulta SELECT * en la tabla y verifique si la columna está allí ...

gmize
fuente
ALTER(y DDL así) en MySQL de hecho comprometen (implícitamente) la transacción. Pero el uso de SELECT * generaría una gran sobrecarga en la red solo para verificar la existencia de la columna. En su lugar, puede intentar SELECT my_col_to_check FROM t LIMIT 0: si mysql genera un error, entonces la columna probablemente no exista (aún así, verifique el error, ¡ya que podría ser un problema de red o lo que sea!); Si no genera ningún error, existe una columna. No estoy seguro de que sea la mejor manera de verificar la existencia de columnas.
Xenos