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にはすべての列の重複セットが含まれていることがわかりました。つまり、すべての列が2回返されました。これが私が得た出力です:

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

Oracle SQL Developerを使用してテーブルを見ると、テーブルには3つの列(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));
}

これは問題なく機能しているようで、重複は返されません。そして疑問に思う人のために:このブログによると、 getColumnName()の代わりにgetColumnLabel()を使用する必要があります。

4

5 に答える 5

28

Oracleでは、接続先のスキーマだけでなく、データベース全体Connection.getMetaData()のメタデータを返します。したがって、の最初の2つの引数として指定する場合、スキーマのみの結果をフィルタリングしているわけではありません。nullmeta.getColumns()

Oracleスキーマの名前をの最初の2つのパラメーターの1つmeta.getColumns()、おそらく2番目のパラメーターに指定する必要があります。

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

あなたの質問の更新で、あなたがケンスターの答えの重要な部分の1つを見逃していることに気づきました。彼は、あなたが持っていない「where 1=0」の「where」句を指定しました。これをオフのままにすると、Oracleはテーブル全体を返そうとするため、これは重要です。そして、すべてのレコードをプルしなかった場合、オラクルはそれらを保持し、ページをめくるのを待ちます。where句を追加してもメタデータが得られますが、オーバーヘッドはありません。

また、私は個人的に「where rownum <1」を使用します。これは、すべてのrownumがそれを超えていることをオラクルがすぐに認識し、「1=0」の各レコードをテストしないほど賢いかどうかわからないためです。

于 2011-08-31T19:28:24.363 に答える
1

skaffmanの答えに加えて-

Oracleで次のクエリを使用します。

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

Javaでのアクセスが制限されている場合は、現在のスキーマ名にアクセスします。

于 2012-08-23T10:36:26.997 に答える
0

これは、JDBC APIによって義務付けられている動作です。getColumnsに最初と2番目のパラメーターとしてnullを渡すことは、検索を絞り込むためにカタログ名もスキーマ名も使用されないことを意味します。 ドキュメントへのリンク。他の一部のJDBCドライバーはデフォルトで異なる動作をすることは事実です(たとえば、MySQLのConnectorJはデフォルトで現在のカタログに制限されます)が、これは標準ではなく、そのように文書化されています

于 2013-01-21T16:58:12.873 に答える