使用 PHP/PDO 检查数据库表是不是存在
Posted
技术标签:
【中文标题】使用 PHP/PDO 检查数据库表是不是存在【英文标题】:Check if a database table exists using PHP/PDO使用 PHP/PDO 检查数据库表是否存在 【发布时间】:2010-12-15 14:33:52 【问题描述】:我想检查我使用 php 和 PDO 连接的数据库中是否存在具有特定名称的表。
它必须适用于所有数据库后端,如 mysql、SQLite 等。
【问题讨论】:
MySQL check if a table exists without throwing an exception的可能重复 【参考方案1】:这是一个检查表是否存在的完整函数。
/**
* Check if a table exists in the current database.
*
* @param PDO $pdo PDO instance connected to a database.
* @param string $table Table to search for.
* @return bool TRUE if table exists, FALSE if no table found.
*/
function tableExists($pdo, $table)
// Try a select statement against the table
// Run it in try-catch in case PDO is in ERRMODE_EXCEPTION.
try
$result = $pdo->query("SELECT 1 FROM $table LIMIT 1");
catch (Exception $e)
// We got an exception (table not found)
return FALSE;
// Result is either boolean FALSE (no table found) or PDOStatement Object (table found)
return $result !== FALSE;
注意:只有在被告知时,PDO 才会抛出异常,默认情况下它是静默的并且不抛出异常。这就是为什么我们也需要检查结果。 See PDO error handling at php.net
【讨论】:
这不能防止 SQL 注入。 @livefree75 也许你可以更具体一点?我在这里没有看到任何客户提供的字段...也许我不确定您在他/她的代码中看到的问题? @livefree75 为什么要保护?如果它在 db 层,则不应在此处插入保护。保护和安全并不意味着到处插入过滤\消毒功能。 如果您想清理,请在函数开始处执行此操作:$table = preg_replace('/[^\da-z_]/i', '', $table);
【参考方案2】:
我建议您使用 DESCRIBE
示例查询:
DESCRIBE `users`
示例 php&pdo:
$tblname = 'users'; //table name
$x = $db->prepare("DESCRIBE `$tblname`");
$x->execute();
$row = $x->fetch();
if ($row)
print 1; //table exists
else
print 0; //table not exists
【讨论】:
【参考方案3】:如果您在同一语句中还有其他主要操作要做,可以使用 e->errorInfo
try
//Your major statements here
catch(PDOException $e)
if($e->errorInfo[1] == 1146)
//when table doesn't exist
【讨论】:
由于权限,您可能希望在生产中使用$e->getCode()
【参考方案4】:
起初,我使用的是公认的答案,但后来我注意到它因空表而失败。这是我现在使用的代码:
function DB_table_exists($db, $table)
GLOBAL $db;
try
$db->query("SELECT 1 FROM $db.$table");
catch (PDOException $e)
return false;
return true;
此代码是我的 PDO 扩展类的摘录。如果表不存在,它将产生错误(并返回 false),但如果表存在和/或为空,则会成功。
【讨论】:
【参考方案5】:这似乎至少适用于 SQLite3,没有例外等:
$select =
"SELECT CASE WHEN EXISTS (SELECT * FROM SQLITE_MASTER WHERE TYPE = 'table' AND NAME = :tableName) THEN 1 ELSE 0 END AS TABLE_EXISTS;";
【讨论】:
你的意思是,这将仅在 SQLite 下工作,因为其他 RDBMS 没有SQLITE_MASTER
表......顾名思义?OP要求数据库- 独立解决方案...
没错,我似乎只是回答了 SQLite 部分,因为当时我正在使用 PDO SQLite。 PHP 并不是我真正的“东西”,但从不存在的表中选择一 (1) 应该会导致异常,因此需要使用已接受答案中所述的代码进行异常处理?【参考方案6】:
如果表不存在,请执行查询,要求数据库创建表:
$string = "CREATE TABLE IF NOT EXISTS " .$table_name . " int(11) NOT NULL AUTO_INCREMENT,
`id` int(3) NOT NULL,
`blabla` int(2) NOT NULL,
`blabla1` int(2) NOT NULL,
`blabla3` varchar(3) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
AUTO_INCREMENT=1 ";
$sql = $conection->prepare($string);
$sql->execute();
【讨论】:
似乎有点矫枉过正......正如其他人所建议的那样,create table
在计算上肯定比简单的select
更昂贵?此外,OP 想要一个适用于所有后端的解决方案——您的解决方案仅适用于 MySQL/MariaDB。【参考方案7】:
作为项目的一部分,创建一个架构视图。
对于 Oracle,它会是这样的
SELECT TABLE_NAME FROM ALL_TABLES
对于Mysql:
SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = 'mydbname'
ETC..
然后在代码中针对视图运行查询。
【讨论】:
问题是关于 PDO。请相应地更新答案。 @sitilge PDO 与手头的问题是正交的。它只是运行查询的工具。这是一个好的答案。 @FélixGagnon-Grenier 确实是一个工具。但是,OP 很可能希望收到this is how you do it with PDO
的答案,不是吗?
@DavidTimothyStrauss 我回滚了您的编辑,因为它完全不合适。它不仅是无效的 sql 代码,而且没有关于如何在查询中实际连接所述变量。
@sitilge 好吧,也许吧。我并不是非常不同意,只是“这就是你使用 PDO 的方式”在每千篇教程中都有解释:它被命名为运行 sql 查询。如果有人无法理解 SQL 代码实际上是要运行的,无论是通过 PDO 还是其他方式,他们也不希望他们知道如何使用详细的答案......【参考方案8】:
这对我有用。这是几个答案的组合:
$table_name = 'your_table_here';
$test = "SELECT 1 FROM " . $table_name . " LIMIT 1";
$test = $db->query($test); //$db needs to be PDO instance
if($test)
return 1; //Table exists
else
return 0; //No table in database
【讨论】:
【参考方案9】:这个完整的功能与 esbite 的答案非常相似,但包含防止 SQL 注入的代码。此外,当相关表格为空时,您可能无法从接受的答案中获得一致的结果。
/**
* This function checks if the table exists in the passed PDO database connection
* @param PDO $pdo - connection to PDO database table
* @param type $tableName
* @return boolean - true if table was found, false if not
*/
function tableExists(PDO $pdo, $tableName)
$mrSql = "SHOW TABLES LIKE :table_name";
$mrStmt = $pdo->prepare($mrSql);
//protect from injection attacks
$mrStmt->bindParam(":table_name", $tableName, PDO::PARAM_STR);
$sqlResult = $mrStmt->execute();
if ($sqlResult)
$row = $mrStmt->fetch(PDO::FETCH_NUM);
if ($row[0])
//table was found
return true;
else
//table was not found
return false;
else
//some PDO error occurred
echo("Could not check if table exists, Error: ".var_export($pdo->errorInfo(), true));
return false;
【讨论】:
这只适用于 MySQL。检查表是否存在不应要求防止 SQL 注入,因为表检查应仅使用程序员指定的值或已知安全生成的名称来完成。如果代码允许非特权用户创建具有任意名称的表,那已经是一个更大的问题了。【参考方案10】:通过 PDO 处理数据库后,您可以这样做:
$tableExists = gettype($dbh->exec("SELECT count(*) FROM $table")) == 'integer';
或者将其包装在一个函数中。
一开始我尝试过使用try/catch,但即使该表不存在,也没有例外。最后检查了 dbh exec 调用返回值的数据类型。如果选择计数匹配,则为整数(即使计数为 0,如果没有结果,则为 false 的布尔值。
我认为这应该适用于 PDO 支持的所有数据库类型,因为语法非常简单。
【讨论】:
如果我的表有 100 万行会怎样? 如果表使用 MyISAM 引擎,这个操作非常快,因为值被存储为元数据 (dev.mysql.com/doc/refman/5.7/en/…) MySQL 已经远离 MyISAM 很长时间了,它远不是唯一一个让行计数变得昂贵的数据库。这也不会在异常模式下处理 PDO。【参考方案11】:在我继续之前,我确实意识到这是一个特定于 MySQL 的解决方案。
虽然这里提到的所有解决方案都可能有效,但我(个人)喜欢防止 PDO 引发异常(个人偏好,仅此而已)。
因此,我使用以下方法来测试表创建:
SHOW TABLES LIKE 'some_table_of_mine';
如果表不存在,则不会生成错误状态,您只需得到一个零结果集。对我来说工作快速且始终如一。
【讨论】:
【参考方案12】:您可以通过使用“SHOW TABLES LIKE 'your_table'”行中的查询然后计算行数来避免依赖错误。我已经在 MySQL 和 PDO 上成功使用了这种方法,但还没有在其他 DB 上进行测试
【讨论】:
确实,这不适用于其他数据库(尽管其他数据库通常与 MySQL 的信息模式和SHOW TABLES
等效)。
@DavidTimothyStrauss 您似乎对改进这个问题很感兴趣,它的答案很棒,但请注意您的编辑建议。您正在更改其他人的内容,有时会从字面上重写答案。如果您觉得答案错误,正确的做法是投反对票并发表评论,以便操作人员可以修复它,而不是使用您自己的方式来修复它。谢谢!【参考方案13】:
我在我的 Web 应用程序中使用 CodeIgniter 做了一些事情来检查数据库是否存在(并且有用),其中任何一个都可以工作:
@$this->load->database();
$v = @$this->db->version()
$tables = @$this->db->list_tables();
如果您在 PHP 设置中启用了 @
,则添加 @
将抑制错误,并检查 version()
和 list_tables()
的结果不仅可用于确定您的数据库是否存在(但它是理智的也)。
【讨论】:
是的,但是您需要为此使用 CodeIgniter 框架(OP 未说明)。此外,至少在 2020 年,您可以简单地使用 if ($db->tableExists('table_name') ...)。【参考方案14】:做:
select 1 from your_table
然后捕获错误。如果您没有收到任何错误,但结果集中有一列包含“1”,则该表存在。
【讨论】:
如果你有很多行,那可能很危险。 @feihtthief:有办法解决这个问题。例如,您只能获取第一行。或者,更好的是,甚至不执行语句,只需准备它。 @MilanBabuškov 我不知道如何准备语句而不是执行告诉人们该表是否存在。我忽略了什么吗? 这个答案没有解决使用 PDO 或 PHP 的问题,在某些情况下,前者在异常处理方面存在细微差别。 如果表为空则失败以上是关于使用 PHP/PDO 检查数据库表是不是存在的主要内容,如果未能解决你的问题,请参考以下文章
PHP PDO 检查 mySQL 表中的多个列并创建不存在的列
如何使用 php pdo 中的 2 个表获取 1 个表用户详细信息?