質問

私は、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()を使用する必要があります。

役に立ちましたか?

解決

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

Oracleスキーマの名前を、<=>の最初の2つのパラメーターのいずれか、おそらく2番目のパラメーターに指定する必要があります。例:

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

これを行わなければならないのは少しいらいらしますが、それがオラクルの人々がJDBCドライバーを実装するために選んだ方法です。

他のヒント

これはあなたの質問に直接答えませんが、別のアプローチはクエリを実行することです:

select * from tablename where 1 = 0

これは、行を選択しなくても、ResultSetを返します。結果セットのメタデータは、選択したテーブルと一致します。何をしているのかにもよりますが、これはより便利です。 tablenameは、選択できるものであれば何でもかまいません。大文字と小文字を区別したり、スキーマがどのスキーマにあるかを心配したりする必要はありません。

質問の更新で、Kensterの回答の重要な部分を見逃していることに気付きました。彼は、「where 1 = 0」という「where」節を指定しましたが、これはありません。これは重要なことです。これを省略すると、oracleはENTIREテーブルを試行して返すためです。また、すべてのレコードを取得しない場合、オラクルはそれらを保持し、ページをめくるのを待ちます。 where句を追加すると、メタデータが得られますが、オーバーヘッドは発生しません。

また、私は個人的に「where rownum <!> lt; 1 '、oracleはすべてのrownumがそれを過ぎていることをすぐに知っているため、' 1 = 0 'の各レコードを試行およびテストしないほどスマートかどうかはわかりません。

スカッフマンの答えに加えて-

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

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top