Question

Je suis occupé par un morceau de code pour obtenir tous les noms de colonnes d'une table à partir d'une base de données Oracle. Le code que j'ai créé ressemble à ceci:

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"));
}

Lorsque j'ai exécuté ce code à ma grande surprise, trop de colonnes ont été renvoyées. Un examen plus attentif a révélé que le ResultSet contenait un ensemble dupliqué de toutes les colonnes, c'est-à-dire que chaque colonne était renvoyée deux fois. Voici le résultat obtenu:

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

Quand je regarde la table avec Oracle SQL Developer, cela montre qu’elle ne contient que trois colonnes (ID, NAME, CITY). J'ai essayé ce code contre plusieurs tables différentes dans ma base de données et certaines fonctionnent très bien, alors que d'autres présentent ce comportement étrange.

Peut-il y avoir un bogue dans le pilote JDBC Oracle? Ou est-ce que je fais quelque chose de mal ici?

Mise à jour: Merci à Kenster . J'ai maintenant un autre moyen de récupérer les noms de colonne. . Vous pouvez les obtenir à partir d'un ResultSet, comme ceci:

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));
}

Cela semble fonctionner correctement et aucun doublon n’est renvoyé! Et pour ceux qui se demandent: selon ce blog devrait utiliser getColumnLabel () au lieu de getColumnName ().

Était-ce utile?

La solution

Dans oracle, Connection.getMetaData() renvoie les métadonnées de la base de données entière , pas uniquement le schéma auquel vous êtes connecté. Ainsi, lorsque vous fournissez null comme les deux premiers arguments à meta.getColumns(), vous ne filtrez pas les résultats uniquement pour votre schéma.

Vous devez indiquer le nom du schéma Oracle dans l'un des deux premiers paramètres de <=>, probablement le deuxième, par exemple.

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

C’est un peu irritant de devoir faire cela, mais c’est ainsi que les spécialistes Oracle ont choisi d’implémenter leur pilote JDBC.

Autres conseils

Cela ne répond pas directement à votre question, mais une autre approche consiste à exécuter la requête:

select * from tablename where 1 = 0

Ceci renverra un ResultSet, même s'il ne sélectionne aucune ligne. Les métadonnées du jeu de résultats correspondront à la table que vous avez sélectionnée. Selon ce que vous faites, cela peut être plus pratique. tablename vous pouvez sélectionner tout ce que vous pouvez sélectionner - vous n'avez pas besoin de corriger le cas ni de vous inquiéter du schéma dans lequel il se trouve.

Dans la mise à jour de votre question, j'ai remarqué que vous avez manqué un élément clé de la réponse de Kenster. Il a spécifié une clause 'où' de 'où 1 = 0', ce que vous n'avez pas. Ceci est important car si vous le laissez désactivé, alors Oracle tentera de renvoyer la table ENTIER. Et si vous ne retirez pas tous les registres, Oracle les conservera, dans l'attente de les feuilleter. En ajoutant cette clause where, vous obtenez toujours les métadonnées, mais sans aucun frais supplémentaire.

De plus, j'utilise personnellement 'where rownum < 1 ', oracle sachant immédiatement que tous les retours sont terminés, et je ne suis pas sûr que ce soit suffisamment intelligent pour ne pas essayer de tester chaque enregistrement pour "1 = 0".

En plus de la réponse de skaffman -

utilisez la requête suivante dans Oracle:

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

pour accéder au nom de votre schéma actuel si vous n’êtes pas autorisé à le faire en Java.

C’est le comportement imposé par l’API JDBC: transmettre les valeurs null en tant que premier et deuxième paramètre à getColumns signifie que ni le nom du catalogue ni le nom du schéma ne sont utilisés pour restreindre la recherche. Lien vers la documentation . Il est vrai que certains autres pilotes JDBC ont un comportement différent par défaut (par exemple, ConnectorJ de MySQL se limite par défaut au catalogue actuel), mais cela n’est pas standard et documenté en tant que tel

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top