【问题标题】:Check if MySQL table exists without using "select from" syntax?检查 MySQL 表是否存在而不使用“select from”语法?
【发布时间】:2012-02-08 09:20:28
【问题描述】:

有没有办法检查一个表是否存在从中选择和检查值?

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

【问题讨论】:

  • @SaurabhChopra 这是针对 SQL Server 的,这是在询问 MySql。

标签: mysql sql


【解决方案1】:

如果您想正确,请使用INFORMATION_SCHEMA

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

或者,您可以使用SHOW TABLES

SHOW TABLES LIKE 'yourtable';

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

【讨论】:

  • 是的,它工作得很好而且很优雅,但仍然使用SELECT...FROM 语法...我在寻找类似EXISTS testtable的东西
  • 马克和我自己说的这样做是正确的方法。 MySql 没有“存在”类型语句。 MySql 中的“Exists”是一个子句,它需要诸如 SELECT、UPDATE 或 DELETE 之类的操作。
  • @Steve 第三个选项不可移植。
  • @SergioTulentsev 不管标签是什么,我更喜欢便携方式而不是专有方式。
  • @Filype 这不是一个真正的问题,因为他只是检查查询是否成功。在表没有行的情况下,查询仍然会成功,只是结果集为空。
【解决方案2】:
SELECT count(*)
FROM information_schema.TABLES
WHERE (TABLE_SCHEMA = 'your_db_name') AND (TABLE_NAME = 'name_of_table')

如果您得到一个非零计数,则该表存在。

【讨论】:

  • 我真的不明白这里发生了什么。我已经检查了答案,因为我现在正在这样做,而且 Sergio Tulentsevs 的答案确实更早(1 分钟)并提供了 3 个解决方案,但这个是最有效的。为什么我要选择更多或其他我想要的东西?在这种情况下,我需要一个“布尔”1/0。表是否存在。我不想限制一切,我不想喜欢任何东西,我不想要任何错误。这应该是公认的答案。
  • 请注意,TEMPORARY TABLE 这不起作用。
【解决方案3】:

您可以查询INFORMATION_SCHEMAtables系统视图:

SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'databasename'
AND table_name = 'testtable';

如果没有返回行,则表不存在。

【讨论】:

    【解决方案4】:

    与其依赖错误,你可以查询INFORMATION_SCHEMA.TABLES来查看表是否存在。如果有记录,它就存在。如果没有记录,则不存在。

    【讨论】:

    • 啊,现在我们越来越近了!我去试试看。
    • @Steve:它仍然是SELECT FROM。 :-)
    【解决方案5】:

    除了 SELECT 之外的所有选项都不允许在 SELECT 中使用数据库名称,所以我写了这个:

    SELECT COUNT(*) AS cnt FROM information_schema.TABLES 
    WHERE CONCAT(table_schema,".",table_name)="db_name.table_name";
    

    【讨论】:

      【解决方案6】:

      这是一个不是 SELECT * FROM 的表

      SHOW TABLES FROM `db` LIKE 'tablename'; //zero rows = not exist
      

      这是从数据库专家那里得到的,这是我被告知的:

      select 1 from `tablename`; //avoids a function call
      select * from INFORMATION_SCHEMA.tables where schema = 'db' and table = 'table' // slow. Field names not accurate
      SHOW TABLES FROM `db` LIKE 'tablename'; //zero rows = does not exist
      

      【讨论】:

      • 最简单高效。
      • 我们在 bash 脚本中使用了它,例如if [[ $(mysql --execute "SHOW TABLES FROM ${DB_NAME} LIKE '${DB_PREFIX}options';") -gt 0 ]]; then stackoverflow.com/a/69889338/1718491
      【解决方案7】:

      只是为了添加一个额外的方法来做到这一点,取决于你可以使用handler for er_no_such_table error:1146 像这样:

      DELIMITER ;;
      CREATE PROCEDURE `insert_in_my_table`(in my_var INT)
      BEGIN
         -- Error number for table not found
         DECLARE CONTINUE HANDLER FOR 1146
         BEGIN
            -- table doesn't exists, do something...
            CREATE TABLE my_table(n INT);
            INSERT INTO my_table (n) values(my_var);
         END;
            -- table does exists, do something...
            INSERT INTO my_table (n) values(my_var);
      END ;;
      DELIMITER ;
      

      【讨论】:

        【解决方案8】:

        您可以执行以下操作:

                    string strCheck = "SHOW TABLES LIKE \'tableName\'";
                    cmd = new MySqlCommand(strCheck, connection);
                    if (connection.State == ConnectionState.Closed)
                    {
                        connection.Open();
                    }
                    cmd.Prepare();
                    var reader = cmd.ExecuteReader();
                    if (reader.HasRows)
                    {                             
                      Console.WriteLine("Table Exist!");
                    }
                    else
                    {                             
                      Console.WriteLine("Table does not Exist!");
                    }
        

        【讨论】:

          【解决方案9】:

          我在 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;
              }
          

          【讨论】:

            【解决方案10】:

            性能对比:

            • MySQL 5.0.77,在一个大约有 11,000 个表的数据库上。
            • 选择一个非最近使用的表,使其不被缓存。
            • 平均每次尝试超过 10 次。 (注意:使用不同的表完成以避免缓存)。

            322 毫秒:show tables like 'table201608';

            691 毫秒:select 1 from table201608 limit 1;

            319 毫秒:SELECT count(*) FROM information_schema.TABLES WHERE (TABLE_SCHEMA = 'mydb') AND (TABLE_NAME = 'table201608');

            请注意,如果您经常运行此程序(例如在短时间内处理许多 HTML 请求),则第 2 次会更快,因为它会平均缓存 200 毫秒或更快。

            【讨论】:

              【解决方案11】:

              显示像“table_name”这样的表格

              如果返回行 > 0,则表存在

              【讨论】:

                【解决方案12】:

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

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

                【讨论】:

                  【解决方案13】:

                  扩展这个answer,可以进一步编写一个函数,根据表是否存在返回TRUE/FALSE:

                  CREATE FUNCTION fn_table_exists(dbName VARCHAR(255), tableName VARCHAR(255))
                    RETURNS BOOLEAN
                    BEGIN
                      DECLARE totalTablesCount INT DEFAULT (
                        SELECT COUNT(*)
                        FROM information_schema.TABLES
                        WHERE (TABLE_SCHEMA COLLATE utf8_general_ci = dbName COLLATE utf8_general_ci)
                          AND (TABLE_NAME COLLATE utf8_general_ci = tableName COLLATE utf8_general_ci)
                      );
                      RETURN IF(
                        totalTablesCount > 0,
                        TRUE,
                        FALSE
                      );
                  END
                  ;
                  
                  
                  SELECT fn_table_exists('development', 'user');
                  

                  【讨论】:

                    【解决方案14】:

                    看完以上所有,我更喜欢下面的说法:

                    SELECT EXISTS(
                           SELECT * FROM information_schema.tables 
                           WHERE table_schema = 'db' 
                           AND table_name = 'table'
                    );
                    

                    它准确地表明你想要做什么,它实际上返回一个“布尔值”。

                    【讨论】:

                    • 这应该是公认的答案。简洁明了
                    • 这不返回布尔值,它返回一个结果集。 var_dump:mysqli_result Object ( [current_field] => 0 [field_count] => 1 [lengths] => [num_rows] => 1 [type] => 0 )
                    【解决方案15】:

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

                    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);
                    

                    如果表格有零行,您将不会得到预期的结果。

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

                    可以这样使用:

                    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 ;
                    

                    【讨论】:

                      【解决方案16】:

                      这是我检查临时表和普通表的“首选”EXISTS 过程。此过程适用于 MySQL 5.6 及更高版本。 @DEBUG 参数是可选的。采用默认架构,但可以在 @s 语句中连接到表。

                      drop procedure if exists `prcDoesTableExist`;
                      delimiter #
                      CREATE PROCEDURE `prcDoesTableExist`(IN pin_Table varchar(100), OUT pout_TableExists BOOL)
                      BEGIN
                          DECLARE `boolTableExists` TINYINT(1) DEFAULT 1;
                          DECLARE CONTINUE HANDLER FOR 1243, SQLSTATE VALUE '42S02' SET `boolTableExists` := 0;
                              SET @s = concat('SELECT null FROM `', pin_Table, '` LIMIT 0 INTO @resultNm');
                          PREPARE stmt1 FROM @s;
                          EXECUTE stmt1;
                          DEALLOCATE PREPARE stmt1;
                          set pout_TableExists = `boolTableExists`; -- Set output variable
                          IF @DEBUG then
                              select IF(`boolTableExists`
                                  , CONCAT('TABLE `', pin_Table, '` exists: ', pout_TableExists)
                                  , CONCAT('TABLE `', pin_Table, '` does not exist: ', pout_TableExists)
                              ) as result;
                          END IF;
                      END #
                      delimiter ;
                      

                      这是带有@debug 的示例调用语句:

                      set @DEBUG = true;
                      call prcDoesTableExist('tempTable', @tblExists);
                      select @tblExists as '@tblExists';
                      

                      变量@tblExists 返回一个布尔值。

                      【讨论】:

                        【解决方案17】:

                        此紧凑方法如果存在则返回 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。

                        【讨论】:

                          【解决方案18】:

                          如果在 2019 年之后阅读本文,请注意 MySQL 5.7 添加了一个table_exists 过程,该过程将确定一个表是否存在,包括临时表。

                          用法: 将@exist 设置为 ''、'BASE TABLE'、'VIEW'、'TEMPORARY' 之一

                          CALL sys.table_exists('db1', 't3', @exists);
                          

                          参考:

                          https://dev.mysql.com/doc/refman/5.7/en/sys-table-exists.html

                          【讨论】:

                            【解决方案19】:

                            在创建 TABLE 之前,始终建议检查该表是否存在于 SQL Server 数据库中。

                            USE [DB_NAME]
                            GO
                            IF OBJECT_ID('table_name', 'U') IS NOT NULL
                            BEGIN
                            PRINT 'Table exists.'
                            END
                            ELSE
                            BEGIN
                            PRINT 'Table does not exist.'
                            END
                            

                            或者 使用 sys.Objects 检查 SQL Server 中是否存在表。

                            USE [DB_NAME]
                            GO
                            IF EXISTS(SELECT 1 FROM sys.Objects
                            WHERE Object_id = OBJECT_ID(N'table_name')
                            AND Type = N'U')
                            BEGIN
                            PRINT 'Table exists.'
                            END
                            ELSE
                            BEGIN
                            PRINT 'Table does not exist.'
                            END
                            

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2010-12-04
                              • 2018-10-07
                              • 1970-01-01
                              • 2017-08-07
                              • 2022-07-07
                              • 1970-01-01
                              相关资源
                              最近更新 更多