有没有一种方法来检查表是否存在,而不选择和检查它的值?

也就是说,我知道我可以去SELECT testcol FROM testtable并检查返回字段的计数,但似乎必须有一个更直接/优雅的方式来做到这一点。


当前回答

我在php中使用这个。

private static function ifTableExists(string $database, string $table): bool
    {
        $query = DB::select("
            SELECT 
                IF( EXISTS 
                    (SELECT * FROM information_schema.COLUMNS
                        WHERE TABLE_SCHEMA = '$database'
                        AND TABLE_NAME = '$table'
                        LIMIT 1),
                1, 0)
                AS if_exists
        ");

        return $query[0]->if_exists == 1;
    }

其他回答

性能比较:

MySQL 5.0.77,在一个大约有11000个表的数据库上。 选择一个非最近使用的表,这样它就不会被缓存。 平均每次超过10次。(注意:做不同的表,以避免缓存)。

322ms:显示'table201608'这样的表;

select 1 from table201608 limit 1;

319ms: SELECT count(*) FROM information_schema。table WHERE (TABLE_SCHEMA = 'mydb') AND (TABLE_NAME = 'table201608');

注意,如果你经常运行这个,比如在短时间内处理很多HTML请求,第2个会更快,因为它平均缓存200毫秒或更快。

这里的答案有几个问题需要注意:

1) INFORMATION_SCHEMA。TABLES不包括TEMPORARY表。

2)使用任何类型的SHOW查询,即SHOW TABLES LIKE 'test_table',将强制返回一个结果集到客户端,这是检查表是否存在服务器端的不希望的行为,从存储过程中也返回一个结果集。

3)正如一些用户提到的,你必须小心如何使用SELECT 1 FROM test_table LIMIT 1。

如果你这样做:

SET @table_exists = 0;
SET @table_exists = (SELECT 1 FROM test_table LIMIT 1);

如果表中没有行,则不会得到预期的结果。

下面是一个适用于所有表(甚至是TEMPORARY表)的存储过程。

它可以这样使用:

SET @test_table = 'test_table';
SET @test_db = NULL;
SET @does_table_exist = NULL;

CALL DoesTableExist(@test_table, @test_db, @does_table_exist);

SELECT @does_table_exist;

代码:

/*
    p_table_name is required
    p_database_name is optional
        if NULL is given for p_database_name, then it defaults to the currently selected database
    p_does_table_exist
        The @variable to save the result to

    This procedure attempts to
        SELECT NULL FROM `p_database_name`.`p_table_name` LIMIT 0;

    If [SQLSTATE '42S02'] is raised, then
        SET p_does_table_exist = 0
    Else
        SET p_does_table_exist = 1

    Info on SQLSTATE '42S02' at:
        https://dev.mysql.com/doc/refman/5.7/en/server-error-reference.html#error_er_no_such_table
*/

DELIMITER $$

DROP PROCEDURE IF EXISTS DoesTableExist
$$

CREATE PROCEDURE         DoesTableExist (
    IN p_table_name VARCHAR(64),
    IN p_database_name VARCHAR(64),
    OUT p_does_table_exist TINYINT(1) UNSIGNED
)
BEGIN
    /* 793441 is used in this procedure for ensuring that user variables have unique names */

    DECLARE EXIT HANDLER FOR SQLSTATE '42S02'
    BEGIN
        SET p_does_table_exist = 0
        ;
    END
    ;


    IF p_table_name IS NULL THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'DoesTableExist received NULL for p_table_name.';
    END IF;


    /* redirect resultset to a dummy variable */

    SET @test_select_sql_793441 = CONCAT(
        "SET @dummy_var_793441 = ("
            " SELECT"
                " NULL"
            " FROM ",
                IF(
                    p_database_name IS NULL,
                    "",
                    CONCAT(
                        "`",
                        REPLACE(p_database_name, "`", "``"),
                        "`."
                    )
                ),
                "`",
                REPLACE(p_table_name, "`", "``"),
                "`"
            " LIMIT 0"
        ")"
    )
    ;

    PREPARE _sql_statement FROM @test_select_sql_793441
    ;
    SET @test_select_sql_793441 = NULL
    ;
    EXECUTE _sql_statement
    ;
    DEALLOCATE PREPARE _sql_statement
    ;

    SET p_does_table_exist = 1
    ;
END
$$

DELIMITER ;

如果想要正确,请使用INFORMATION_SCHEMA。

SELECT * 
FROM information_schema.tables
WHERE table_schema = 'yourdb' 
    AND table_name = 'testtable'
LIMIT 1;

或者,您也可以使用SHOW TABLES

SHOW TABLES LIKE 'yourtable';

如果结果集中有行,则表存在。

如果存在则返回1,不存在则返回0。

set @ret = 0; 
SELECT 1 INTO @ret FROM information_schema.TABLES 
         WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'my_table'; 
SELECT @ret;

可以放入mysql函数中

DELIMITER $$
CREATE FUNCTION ExistTable (_tableName varchar(255))
RETURNS tinyint(4)
SQL SECURITY INVOKER
BEGIN
  DECLARE _ret tinyint;
  SET _ret = 0;
  SELECT
    1 INTO _ret
  FROM information_schema.TABLES
  WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME = _tablename LIMIT 1;
  RETURN _ret;
END
$$
DELIMITER ;

并称之为

Select ExistTable('my_table');

如果存在则返回1,如果不存在则返回0。

上述修改后的解决方案不需要明确了解当前数据库。这样就更灵活了。

SELECT count(*) FROM information_schema.TABLES WHERE TABLE_NAME = 'yourtable' 
AND TABLE_SCHEMA in (SELECT DATABASE());