【问题标题】:Check if table exists [duplicate]检查表是否存在[重复]
【发布时间】:2011-02-25 22:23:47
【问题描述】:

我有一个嵌入了数据库的桌面应用程序。当我执行我的程序时,我需要检查特定表是否存在,如果不存在则创建它。

如果我的数据库有一个名为 conn 的 Connection 对象,我该如何检查呢?

【问题讨论】:

  • 请在您的问题中更具体。

标签: java jdbc


【解决方案1】:
DatabaseMetaData dbm = con.getMetaData();
// check if "employee" table is there
ResultSet tables = dbm.getTables(null, null, "employee", null);
if (tables.next()) {
  // Table exists
}
else {
  // Table does not exist
}

【讨论】:

  • 确保当您使用表名时,它没有使用下划线等模式字符,例如“employee_reports”。我被这种情况所困扰,因为一些元数据实现使用模式匹配。最好使用 if 中的简单 table.equals("employee_reports") 语句仔细检查结果集
  • 同样的代码也适用于 postgres jdbc。谢谢。
  • 请注意,此方法将触发加载有关新创建连接的整个数据库的信息。根据数据库大小,连接速度可能需要 2-5 秒或更长时间。在我们有大约 2000 个集成测试的项目中,它放慢了一个小时(每个测试都使用新创建的方案)。
【解决方案2】:

您可以使用可用的元数据:

  DatabaseMetaData meta = con.getMetaData();
  ResultSet res = meta.getTables(null, null, "My_Table_Name", 
     new String[] {"TABLE"});
  while (res.next()) {
     System.out.println(
        "   "+res.getString("TABLE_CAT") 
       + ", "+res.getString("TABLE_SCHEM")
       + ", "+res.getString("TABLE_NAME")
       + ", "+res.getString("TABLE_TYPE")
       + ", "+res.getString("REMARKS")); 
  }

请参阅here 了解更多详情。还要注意the JavaDoc 中的注意事项。

【讨论】:

  • 您从服务器请求所有表,然后在本地浏览这些名称。如果您只想检查表'X'是否存在,那不是很有效。你会想要使用getTables() 方法的第三个参数!!! (而不是像你一样使用'null')
  • @nolan6000 - 注明并修正。谢谢
  • 如果表名带有schema,这个解决方案不起作用,所以要小心。要提供架构,您应该使用meta.getTables("Schema_Name", null, "My_Table_Name", new String[] {"TABLE"})
  • @AnupKumarGupta:这取决于您使用的 DBMS,但可能是的。通常只列出可用的表是不受限制的。
  • javadoc 上的注释有点吓人:Note: Some databases may not return information for all tables. 除非您知道您的供应商确实完全支持它,否则很难依赖它。
【解决方案3】:

我实际上并没有发现这里提供的任何解决方案是完全完整的,所以我将添加我自己的解决方案。这里没有什么新鲜事。您可以从其他提供的解决方案以及各种 cmets 中将其拼接在一起。

您至少需要确保两件事:

  1. 确保将表名传递给getTables() method, 而不是传递一个空值。在第一种情况下,您让 数据库服务器在您请求的第二秒内为您过滤结果 来自服务器的 all 表列表,然后过滤列表 本地。如果您只搜索一个,前者要快得多 单表。

  2. 确保检查结果集中的表名是否为等号 匹配。原因是getTables() 进行模式匹配 表的查询和_ 字符是SQL 中的通配符。 假设您正在检查是否存在名为 EMPLOYEE_SALARY。然后,您也会在 EMPLOYEESSALARY 上找到匹配项 这不是你想要的。

哦,记得关闭这些结果集。从 Java 7 开始,您可能希望为此使用 try-with-resources statement

这是一个完整的解决方案:

public static boolean tableExist(Connection conn, String tableName) throws SQLException {
    boolean tExists = false;
    try (ResultSet rs = conn.getMetaData().getTables(null, null, tableName, null)) {
        while (rs.next()) { 
            String tName = rs.getString("TABLE_NAME");
            if (tName != null && tName.equals(tableName)) {
                tExists = true;
                break;
            }
        }
    }
    return tExists;
}

您可能需要考虑在 getTables() 调用中作为 types 参数(第 4 个参数)传递的内容。通常我会离开null,因为你不想限制自己。 VIEW 和 TABLE 一样好,对吧?如今,许多数据库允许您通过 VIEW 进行更新,因此在大多数情况下将自己限制为仅 TABLE 类型并不是可行的方法。 YMMV。

【讨论】:

  • 您可能需要将tName.equals(tableName) 更改为tName.equals(tableName.toLowerCase()),如果tableName 为大写则将无法使用。
  • @Searene。问题不在于任何特定的数据库。您是对的,需要考虑这种情况,但这取决于数据库。您甚至可以更改某些数据库,例如 MS SQL 服务器支持不区分大小写和区分大小写,具体取决于您如何设置“COLLATION”的值。所以你的观点是正确的,只是很难想出一个适用于任何场景的通用解决方案。
【解决方案4】:

添加到 Gaby 的帖子中,我的 jdbc getTables() for Oracle 10g 需要全部大写才能工作:

"employee" -> "EMPLOYEE"

否则我会得到一个异常:

java.sql.SqlExcepcion 耗尽结果集

(即使“员工”在架构中)

【讨论】:

    【解决方案5】:
        /**
     * Method that checks if all tables exist
     * If a table doesnt exist it creates the table
     */
    public void checkTables() {
        try {
            startConn();// method that connects with mysql database
            String useDatabase = "USE " + getDatabase() + ";";
            stmt.executeUpdate(useDatabase);
            String[] tables = {"Patients", "Procedures", "Payments", "Procedurables"};//thats table names that I need to create if not exists
            DatabaseMetaData metadata = conn.getMetaData();
    
            for(int i=0; i< tables.length; i++) {
                ResultSet rs = metadata.getTables(null, null, tables[i], null);
                if(!rs.next()) {
                    createTable(tables[i]);
                    System.out.println("Table " + tables[i] + " created");
                }
            }
        } catch(SQLException e) {
            System.out.println("checkTables() " + e.getMessage());
        }
        closeConn();// Close connection with mysql database
    }
    

    【讨论】:

      【解决方案6】:

      如果使用 jruby,这里是一个代码 sn-p 来返回一个 db 中所有表的数组。

      require "rubygems"
      require "jdbc/mysql"
      Jdbc::MySQL.load_driver
      require "java"
      
      def get_database_tables(connection, db_name)
        md = connection.get_meta_data
        rs = md.get_tables(db_name, nil, '%',["TABLE"])
      
        tables = []
        count = 0
        while rs.next
          tables << rs.get_string(3)
        end #while
        return tables
      end
      

      【讨论】:

        猜你喜欢
        • 2012-02-18
        • 2013-08-06
        • 2018-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-12
        • 2013-05-11
        • 2019-05-28
        相关资源
        最近更新 更多