18

我正忙于编写一段代码以从 Oracle 数据库中获取表的所有列名。我想出的代码如下所示:

DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection(
  "jdbc:oracle:thin:@<server>:1521:<sid>", <username>, <password>);

DatabaseMetaData meta = conn.getMetaData();
ResultSet columns = meta.getColumns(null, null, "EMPLOYEES", null);
int i = 1;
while (columns.next())
{
  System.out.printf("%d: %s (%d)\n", i++, columns.getString("COLUMN_NAME"), 
    columns.getInt("ORDINAL_POSITION"));
}

当我运行此代码时,令我惊讶的是返回了太多列。仔细观察会发现 ResultSet 包含所有列的重复集,即每列返回两次。这是我得到的输出:

1: ID (1)
2: NAME (2)
3: CITY (3)
4: ID (1)
5: NAME (2)
6: CITY (3)

当我使用 Oracle SQL Developer 查看该表时,它显示该表只有三列(ID、NAME、CITY)。我已经针对我的数据库中的几个不同的表尝试了这段代码,其中一些工作正常,而另一些则表现出这种奇怪的行为。

Oracle JDBC 驱动程序中是否存在错误?还是我在这里做错了什么?


更新:感谢Kenster,我现在有了另一种检索列名的方法。您可以从 ResultSet 中获取它们,如下所示:

DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@<server>:1521:<sid>", <username>, <password>);

Statement st = conn.createStatement();
ResultSet rset = st.executeQuery("SELECT * FROM \"EMPLOYEES\"");
ResultSetMetaData md = rset.getMetaData();
for (int i=1; i<=md.getColumnCount(); i++)
{
    System.out.println(md.getColumnLabel(i));
}

这似乎工作得很好,并且没有返回任何重复项!对于那些想知道的人:根据这篇博客,您应该使用 getColumnLabel() 而不是 getColumnName()。

4

5 回答 5

28

在 oracle 中,Connection.getMetaData()返回整个数据库的元数据,而不仅仅是您碰巧连接到的模式。因此,当您null将前两个参数提供给 时meta.getColumns(),您不会仅过滤架构的结果。

您需要将 Oracle 模式的名称提供给 的前两个参数之一meta.getColumns(),可能是第二个参数,例如

meta.getColumns(null, "myuser", "EMPLOYEES", null);

这样做有点烦人,但这是 Oracle 人员选择实现其 JDBC 驱动程序的方式。

于 2009-10-21T14:37:18.883 回答
16

这不会直接回答您的问题,但另一种方法是执行查询:

select * from tablename where 1 = 0

这将返回一个 ResultSet,即使它没有选择任何行。结果集元数据将与您从中选择的表匹配。根据您的操作,这可能更方便。tablename可以是您可以选择的任何内容——您不必正确判断大小写或担心它所在的模式。

于 2009-10-22T18:55:17.790 回答
3

在更新您的问题时,我注意到您错过了 Kenster 答案的一个关键部分。他指定了“where 1 = 0”的“where”子句,而你没有。这很重要,因为如果您不使用它,oracle 将尝试返回整个表。如果你不把所有的记录都拉出来,oracle 会保留它们,等待你翻阅它们。添加 where 子句仍会为您提供元数据,但不会产生任何开销。

另外,我个人使用'where rownum < 1',因为oracle 立即知道所有rownum 都超过了它,而且我不确定它是否足够聪明,不会尝试测试每条记录是否为'1 = 0'。

于 2011-08-31T19:28:24.363 回答
1

In addition to skaffman's answer -

use the following query in Oracle:

select sys_context( 'userenv', 'current_schema' ) from dual;  

to access your current schema name if you are restricted to do so in Java.

于 2012-08-23T10:36:26.997 回答
0

这是 JDBC API 强制要求的行为 - 将空值作为第一个和第二个参数传递给 getColumns 意味着既不使用目录名称也不使用模式名称来缩小搜索范围。 链接到文档。确实,其他一些 JDBC 驱动程序在默认情况下具有不同的行为(例如 MySQL 的 ConnectorJ 默认限制为当前目录),但这不是标准的,因此记录在案

于 2013-01-21T16:58:12.873 回答