我忙于编写一段代码来获取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));
}
这似乎工作正常,不会返回重复项!对于那些想知道的人:根据this blog,您应该使用getColumnLabel()而不是getColumnName()。
答案 0 :(得分:25)
在oracle中,Connection.getMetaData()
返回整个数据库的元数据,而不仅仅是您碰巧连接到的模式。因此,当您提供null
作为meta.getColumns()
的前两个参数时,您不会仅仅过滤模式的结果。
您需要将Oracle模式的名称提供给meta.getColumns()
的前两个参数之一,可能是第二个参数,例如
meta.getColumns(null, "myuser", "EMPLOYEES", null);
这样做有点恼人,但这就是Oracle人员选择实现JDBC驱动程序的方式。
答案 1 :(得分:15)
这不会直接回答您的问题,但另一种方法是执行查询:
select * from tablename where 1 = 0
这将返回ResultSet,即使它没有选择任何行。结果集元数据将与您选择的表匹配。根据您正在做的事情,这可能更方便。 tablename
可以是您可以选择的任何内容 - 您无需了解案例或担心其所处的架构。
答案 2 :(得分:3)
在您的问题更新中,我注意到您错过了Kenster答案中的一个关键部分。他指定了'where 1 = 0'的'where'子句,这是你没有的。这很重要,因为如果你关闭它,那么oracle将尝试返回ENTIRE表。如果你没有把所有的记录都拉过来,oracle会把它们拿到,等着你翻阅它们。添加where子句仍然为您提供元数据,但没有任何开销。
另外,我个人使用'where rownum&lt; 1',因为oracle立即知道所有的rownums都已过去了,而且我不确定它是否足够聪明,不能尝试测试每个记录的'1 = 0'。
答案 3 :(得分:1)
除了skaffman的回答 -
在Oracle中使用以下查询:
select sys_context( 'userenv', 'current_schema' ) from dual;
如果您在Java中限制使用,则访问当前的模式名称。
答案 4 :(得分:0)
这是JDBC API强制执行的行为 - 将空值作为第一个和第二个参数传递给getColumns意味着既不使用目录名称也不使用模式名称来缩小搜索范围。 Link to the documentation。确实,其他一些JDBC驱动程序默认具有不同的行为(例如MySQL的ConnectorJ默认限制为当前目录),但这不是标准的,并且记录为