MySQL,使用SQL检查表中是否存在列


130

我正在尝试编写一个查询,该查询将检查MySQL中的特定表是否具有特定列,如果没有,请创建该列。否则什么都不做。在任何企业级数据库中,这实际上都是一个简单的过程,但是MySQL似乎是一个例外。

我以为

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;

可以,但是失败很严重。有办法吗?



为什么不创建它呢?如果存在,则创建将失败,但是您不在乎。
Brian Hooper 2010年

创建发生在事务内部,而失败将终止整个事务,可悲却是真实的
10

@haim —比起平视,但您的链接中建议的查询仅在过程内起作用:(
clops

2
DDL语句在当前事务中导致隐式提交。dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
MCHL

Answers:


259

这对我来说很好。

SHOW COLUMNS FROM `table` LIKE 'fieldname';

使用PHP就像...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;

8
问题不在于如何使用php + sql或java + sql来做到这一点,而是如何使用纯sql / mysql来做到这一点,因此
下降

61
您回答了这个问题+一些对我有帮助的信息,也许对其他人也有所帮助,+ 1
Francisco Presencia

@Mfoo谢谢Mfoo,您拯救了我的一天!像魅力一样工作。除了为此任务创建过程之外,最好的解决方案之一。
webblover 2014年

8
Yura:纯SQL / MySQL答案是第一部分,他说使用“ SHOW COLUMNS FROM table LIKE'fieldname'”。您可以不理会PHP代码,这只是碰巧使用PHP时检索和解释结果的一种方法的示例。
2014年

1
@codenamezero我假设您指的是使用MSSQL,这个问题与MySQL有关。请参阅此帖子以获取MSSQL
Mfoo

158

@julio

感谢您的SQL示例。我尝试了该查询,但我认为它需要进行一些改动才能使其正常运行。

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

那对我有用。

谢谢!


从我的有限研究看来,并非所有托管环境都具有information_schema数据库。我使用过的所有cpanel环境都有它。提供的解决方案取决于此数据库现有的数据库。
cardi777 2014年

2
这个答案比使用“ SHOW COLUMNS”更好,因为它使用ANSI标准方式来获取表信息,这与MySQL专用的SHOW COLUMNS不同。因此,该解决方案将与其他数据库一起使用。使用“ information_schema”听起来很奇怪,您会认为这不是执行此操作的标准SQL方法,但事实并非如此。
2014年

5
请注意,此答案只会为您提供有关该列的存在的信息。如果要有条件地执行某些DDL语句,则必须将整个程序包装在允许诸如的语句之类的过程中IF。有关如何包装过程的示例,请参见stackoverflow.com/questions/7384711/…列和条件DML语句的测试。
Christopher Schultz 2014年

@Iain:stackoverflow.com/questions/32962149/…我已经参考了您的答案
Amar Singh

这比下面的“ SHOW COLUMNS”方法更好,因为可以在参数化查询中使用它来减少SQL注入的风险。只需添加即可使用DATABASE()函数填充TABLE_SCHEMA列。
安德鲁(Andrew)

16

只是为了帮助正在寻找@Mchl描述的具体示例的任何人,请尝试类似

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

如果返回false(零结果),则说明该列不存在。


2
我认为应该是TABLE_NAME = 'my_table'SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'
TABLE_SCHEMA

10

以下是使用不带information_schema数据库的纯PHP的另一种方法:

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

您为什么要避免使用information_schema?它仅出于此目的而存在。(此外,该线程已经很老了,已经得到了答复。)
Leigh

1
在我的测试中,这比使用information_schema快10-50倍。它确实要求该表至少有一行,您不能总是保证这一点。
Martijn

isset()如果数组键存在但值为NULL,则将抛出“ false” 。最array_key_exists()好像if( !array_key_exists( 'my_new_column', $mycol ) )
Paul Geisler

1
这个答案使我变得面目全非,因为我忽略了一个简单的isset()检查。它不能解决问题,但是如果您已经需要执行select查询并将结果存储在内存中,则更好。
虹吸

10

我把这个存储过程与@lain上面的注释一起扔了起来,如果您需要多次调用它(并且不需要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 ;

与...合作 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 |
+----------+

MIster @quickshiftin,非常感谢。这可以帮助我来检查表是可到期,通过检查,如果有一个ExpirationDate领域。😊
Jeancarlo Fontalvo

@JeancarloFontalvo我的荣幸!还要签出我的mysql-inspectors项目,这是我开始使用高级方法检查模式的项目
quickshiftin

1
OMG就像图书馆😱。感谢您分享它先生!
Jeancarlo Fontalvo

8

从信息模式中仅选择column_name,然后将此查询的结果放入变量中。然后测试变量以确定表是否需要更改。

PS也不要为COLUMNS表指定TABLE_SCHEMA。


1
我是MySQL的新手,您可以在此处发布一个小例子吗?
2010年

2

我正在使用以下简单脚本:

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

如果您已经连接到数据库,它将起作用。


仅当表也恰好也有数据行时,这才起作用。但是,如果表为空,则无法使用。
2014年

1
并不完美,使用旧驱动程序,如果表为空,则无法正常工作,输入未转义,但我喜欢您如何一行完成代码。+1
我曾经摔过一只熊。

1

非常感谢Mfoo,他提供了非常不错的脚本来动态添加表(如果表中不存在)。我已经用PHP改善了他的答案。该脚本还可以帮助您查找实际需要多少个表“添加列” mysql命令。只是品尝食谱。像魅力一样工作。

<?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/>';
}
?>

1

这适用于我的示例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());}     
}

0

请勿将ALTER TABLE / MODIFY COLS或任何其他此类table mod操作放入TRANSACTION中。事务是为了能够回退QUERY失败而不是为ALTERATIONS ...而失败,它将在每次事务中出错。

只需在表上运行SELECT *查询并检查该列是否存在...


ALTER(和类似的DDL)确实在MySQL中(隐式地)提交了事务。但是,使用SELECT *仅检查该列的存在将在网络中产生大量开销。您可以尝试尝试SELECT my_col_to_check FROM t LIMIT 0:如果mysql产生错误,则列可能不存在(仍然,请检查错误,因为它可能是网络问题或其他问题!);如果没有错误,则列存在。我不确定这是检查列是否存在的最佳方法。
Xenos
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.