使用 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 个表用户详细信息?

使用golang检查数据库表是不是存在

如何使用 shell 脚本检查 MySQL 数据库中是不是存在表?

如何检查数据库中是不是存在表或列?

检查访问数据库是不是存在表