Domanda

Sono impegnato in un pezzo di codice per ottenere tutti i nomi di colonna di una tabella da un database Oracle. Il codice che ho inventato è simile al seguente:

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

Quando ho eseguito questo codice con mia sorpresa, sono state restituite troppe colonne. Uno sguardo più attento ha rivelato che il ResultSet conteneva un set duplicato di tutte le colonne, ovvero ogni colonna veniva restituita due volte. Ecco l'output che ho ottenuto:

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

Quando guardo la tabella usando Oracle SQL Developer, mostra che la tabella ha solo tre colonne (ID, NAME, CITY). Ho provato questo codice su diverse tabelle nel mio database e alcuni funzionano bene, mentre altri mostrano questo strano comportamento.

Potrebbe esserci un bug nel driver Oracle JDBC? O sto facendo qualcosa di sbagliato qui?


Aggiornamento: grazie a Kenster ora ho un modo alternativo per recuperare i nomi delle colonne . Puoi ottenerli da un ResultSet, in questo modo:

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

Questo sembra funzionare bene e non vengono restituiti duplicati! E per chi si chiede: secondo questo blog tu dovrebbe usare getColumnLabel () invece di getColumnName ().

È stato utile?

Soluzione

In Oracle, Connection.getMetaData() restituisce metadati per il intero database, non solo per lo schema a cui ti capita di essere connesso. Quindi quando fornisci null come primi due argomenti a meta.getColumns(), non stai filtrando i risultati solo per il tuo schema.

Devi fornire il nome dello schema Oracle a uno dei primi due parametri di <=>, probabilmente il secondo, ad es.

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

È un po 'irritante doverlo fare, ma è così che la gente di Oracle ha scelto di implementare il proprio driver JDBC.

Altri suggerimenti

Questo non risponde direttamente alla tua domanda, ma un altro approccio è quello di eseguire la query:

select * from tablename where 1 = 0

Questo restituirà un ResultSet, anche se non seleziona alcuna riga. I metadati del set di risultati corrisponderanno alla tabella selezionata. A seconda di cosa stai facendo, questo può essere più conveniente. tablename può essere qualsiasi cosa su cui puoi selezionare: non devi correggere il caso o preoccuparti dello schema in cui si trova.

Nell'aggiornamento alla tua domanda ho notato che hai perso una parte fondamentale della risposta di Kenster. Ha specificato una clausola 'dove' di 'dove 1 = 0', che non hai. Questo è importante perché se lo lasci spento, allora Oracle tenterà di restituire l'INTERA tabella. E se non riesci a salvare tutti i record, l'oracolo li terrà, aspettando che tu li sfogli. L'aggiunta di quella clausola where ti dà ancora i metadati, ma senza alcun sovraccarico.

Inoltre, uso personalmente 'where rownum < 1 ", poiché l'oracolo sa immediatamente che tutti i rown sono passati, e non sono sicuro che sia abbastanza intelligente da non provare e testare ogni record per" 1 = 0 ".

Oltre alla risposta di skaffman -

utilizza la seguente query in Oracle:

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

per accedere al nome del tuo schema attuale se sei limitato a farlo in Java.

Questo è il comportamento richiesto dall'API JDBC: passare null come primo e secondo parametro a getColumns significa che né il nome del catalogo né il nome dello schema vengono utilizzati per restringere la ricerca. Link alla documentazione . È vero che alcuni altri driver JDBC hanno un comportamento diverso per impostazione predefinita (ad esempio ConnectorJ di MySQL per impostazione predefinita si limita al catalogo corrente), ma questo non è standard e documentato come tale

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top