MySQL, Verifique se existe uma coluna em uma tabela com SQL

130

Eu estou tentando escrever uma consulta que verifique se uma tabela específica no MySQL tem uma coluna específica e, se não - crie-a. Caso contrário, não faça nada. Este é realmente um procedimento fácil em qualquer banco de dados de classe empresarial, mas o MySQL parece ser uma exceção.

Eu pensei 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;

funcionaria, mas falha muito. Há algum jeito?

clops
fonte
Por que não apenas criá-lo? Se existir, a criação falhará, mas você não se importa.
Brian Hooper
a criação ocorre dentro de uma transação e o fracasso irá encerrar toda a transação, triste mas é verdade
Clops
@haim - thans para os headups, mas a consulta sugerida no seu link funciona apenas dentro de um procedimento :(
clops
2
Instruções DDL causam confirmação implícita na transação atual. dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
Mchl

Respostas:

259

Isto funciona bem para mim.

SHOW COLUMNS FROM `table` LIKE 'fieldname';

Com o PHP seria algo como ...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;
Mfoo
fonte
8
A questão não é como fazer isso usando php + sql ou java + sql, é como fazer isso usando puro sql / mysql daí o downvote
Yuriy Nakonechnyy
61
Você responde à pergunta + algumas informações que me ajudaram e provavelmente outras, +1
Francisco Presencia
@Mfoo Obrigado Mfoo, você salvou meu dia! Funciona como charme. Uma das melhores soluções, além de criar procedimentos para esta tarefa.
Webblover
8
Yura: A resposta SQL / MySQL pura é a primeira parte em que ele diz usar "SHOW COLUMNS FROM table LIKE 'fieldname'". Você pode desconsiderar o código PHP, esse é apenas um exemplo de uma maneira de recuperar e interpretar o resultado, se você estiver usando PHP.
orrd 25/03
1
@codenamezero Suponho que você esteja se referindo ao uso do MSSQL, esta pergunta foi referente ao MySQL. consulte esta publicação para MSSQL
Mfoo
158

@julio

Obrigado pelo exemplo SQL. Tentei a consulta e acho que precisa de uma pequena alteração para fazê-la funcionar corretamente.

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

Isso funcionou para mim.

Obrigado!

Iain
fonte
Parece da minha pesquisa limitada que nem todos os ambientes de hospedagem têm um banco de dados de information_schema. Todos os ambientes cpanel que eu usei têm. Essa solução fornecida depende desse banco de dados existente.
cardi777
2
Esta resposta é melhor do que usar "SHOW COLUMNS" porque usa a maneira padrão ANSI para obter informações da tabela, ao contrário de SHOW COLUMNS, que é específico do MySQL. Portanto, esta solução funcionará com outros bancos de dados. Usar "information_schema" parece estranho e você pensaria que não seria a maneira padrão do SQL de fazer isso, mas é.
orrd 25/03
5
Observe que esta resposta fornece apenas as informações sobre a existência da coluna. Se você deseja executar condicionalmente algumas instruções DDL, será necessário agrupar tudo em um procedimento que permita instruções como IFetc. Consulte stackoverflow.com/questions/7384711/… para obter um exemplo de como agrupar um procedimento o teste para a coluna e a instrução DML condicional.
Christopher Schultz
@Iain: stackoverflow.com/questions/32962149/... tenho referiu a sua resposta
Amar Singh
Isso é melhor do que a abordagem "SHOW COLUMNS" abaixo, pois pode ser usada em consultas parametrizadas, reduzindo o risco de injeção de SQL. Só queria adicionar você pode usar a função DATABASE () para preencher a coluna TABLE_SCHEMA.
Andrew
16

Apenas para ajudar quem está procurando um exemplo concreto do que o @Mchl estava descrevendo, tente algo como

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

Se retornar falso (zero resultado), você saberá que a coluna não existe.

julio
fonte
2
Eu acredito que deve ser TABLE_NAME = 'my_table', TABLE_SCHEMA é o esquema da tabela é no IE.SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'
AaronHolland
10

A seguir, é outra maneira de fazer isso usando PHP simples, sem o banco de dados 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
fonte
Por que você deseja evitar o uso do information_schema? Existe apenas para esse fim. (Além disso, esta discussão é bastante antiga e já foi respondida.)
Leigh
1
Nos meus testes, isso é cerca de 10 a 50x mais rápido do que usar o information_schema. Requer que a tabela tenha pelo menos uma linha, o que você nem sempre pode garantir.
Martijn 28/01
isset()trow 'false' se a chave da matriz existir, mas o valor for NULL . É melhor usar array_key_exists()comoif( !array_key_exists( 'my_new_column', $mycol ) )
Paul Geisler
1
Essa resposta me deixou sem graça porque esqueci uma isset()verificação simples . Não resolve a questão, mas é melhor se você já precisar executar a consulta de seleção e ter o resultado na memória.
Sifão
10

Joguei esse procedimento armazenado junto com os comentários de @ lain acima, um pouco legal se você precisar chamá-lo mais do que algumas vezes (e não precisar de 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 ;

Trabalhando com 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 |
+----------+
troca rápida
fonte
MIster @quickshiftin, muito obrigado. Isso me ajuda a verificar se uma tabela é expirável , verificando se há um ExpirationDatecampo. Jean
Jeancarlo Fontalvo
@JeancarloFontalvo My prazer! Também verifique o meu projeto de mysql-inspectors que iniciei para inspecionar o esquema com métodos de nível superior.
quickshiftin
1
OMG É como uma biblioteca 😱. Obrigado por compartilhar, senhor!
Jeancarlo Fontalvo
8

Selecione apenas column_name no esquema de informações e coloque o resultado dessa consulta na variável Em seguida, teste a variável para decidir se a tabela precisa de alteração ou não.

PS Não se esqueça de especificar também a tabela TABLE_SCHEMA para COLUMNS.

Mchl
fonte
1
Eu sou bastante novo no MySQL, você pode talvez postar um pequeno exemplo aqui?
clops
2

Eu estou usando este script simples:

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

Funciona se você já estiver conectado ao banco de dados.

vio
fonte
Isso só funcionaria se a tabela também tivesse linhas de dados. Mas se a mesa estivesse vazia, isso não funcionaria.
orrd 25/03
1
não é perfeito, usa drivers antigos, não funciona se a tabela estiver vazia, as entradas não escaparam, mas eu gosto de como você fez isso em uma linha. +1
Lutei com um urso uma vez.
1

Muito obrigado ao Mfoo, que colocou o script muito bom para adicionar colunas dinamicamente, se não existir na tabela. Eu melhorei sua resposta com PHP . O roteiro também ajuda a encontrar quantas tabelas realmente necessário 'Add coluna' comand mysql. Basta provar a receita. Funciona como charme.

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

Este trabalho para mim com amostra DOP:

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
fonte
0

NÃO coloque ALTER TABLE / MODIFY COLS ou quaisquer outras operações de modificação de tabela dentro de uma TRANSACTION. As transações destinam-se a reverter uma falha de QUERY, não para ALTERations ... ela ocorrerá sempre de erro em uma transação.

Basta executar uma consulta SELECT * na tabela e verificar se a coluna está lá ...

gmize
fonte
ALTER(e DDL assim) no MySQL de fato confirmam (implicitamente) a transação. Mas o uso de SELECT * geraria uma grande sobrecarga na rede para apenas verificar a existência da coluna. Você pode tentar SELECT my_col_to_check FROM t LIMIT 0: se o mysql gerar um erro, provavelmente a coluna não existe (ainda assim, verifique o erro, pois pode ser um problema de rede ou o que seja!); se não gerar erro, a coluna existe. Não sei se é a melhor maneira de verificar a existência de colunas.
Xenos