Pregunta

Estoy ocupado en un fragmento de código para obtener todos los nombres de columna de una tabla de una base de datos Oracle. El código que se me ocurrió se ve así:

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

Cuando ejecuté este código para mi sorpresa, se devolvieron demasiadas columnas. Una mirada más cercana reveló que ResultSet contenía un conjunto duplicado de todas las columnas, es decir, cada columna se devolvió dos veces. Aquí está la salida que obtuve:

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

Cuando miro la tabla usando Oracle SQL Developer, muestra que la tabla solo tiene tres columnas (ID, NOMBRE, CIUDAD). He intentado este código con varias tablas diferentes en mi base de datos y algunas funcionan bien, mientras que otras exhiben este comportamiento extraño.

¿Podría haber un error en el controlador JDBC de Oracle? ¿O estoy haciendo algo mal aquí?


Actualización: Gracias a Kenster ahora tengo una forma alternativa de recuperar los nombres de columna . Puede obtenerlos de un ResultSet, como este:

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

¡Esto parece funcionar bien y no se devuelven duplicados! Y para aquellos que se preguntan: de acuerdo con este blog usted debería usar getColumnLabel () en lugar de getColumnName ().

¿Fue útil?

Solución

En Oracle, Connection.getMetaData() devuelve metadatos para la base de datos completa , no solo el esquema al que está conectado. Entonces, cuando proporciona null como los dos primeros argumentos para meta.getColumns(), no está filtrando los resultados solo para su esquema.

Debe proporcionar el nombre del esquema de Oracle a uno de los dos primeros parámetros de <=>, probablemente el segundo, por ejemplo,

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

Es un poco irritante tener que hacer esto, pero esa es la forma en que la gente de Oracle eligió implementar su controlador JDBC.

Otros consejos

Esto no responde directamente a su pregunta, pero otro enfoque es ejecutar la consulta:

select * from tablename where 1 = 0

Esto devolverá un ResultSet, aunque no seleccione ninguna fila. Los metadatos del conjunto de resultados coincidirán con la tabla que seleccionó. Dependiendo de lo que esté haciendo, esto puede ser más conveniente. tablename puede ser cualquier cosa que pueda seleccionar: no tiene que corregir el caso ni preocuparse por el esquema en el que se encuentra.

En la actualización de su pregunta, noté que se perdió una parte clave de la respuesta de Kenster. Especificó una cláusula 'where' de 'where 1 = 0', que no tiene. Esto es importante porque si lo deja apagado, entonces Oracle intentará devolver la tabla COMPLETA. Y si no retira todos los registros, Oracle se quedará con ellos, esperando que los revise. Agregar esa cláusula where aún te proporciona los metadatos, pero sin ninguna sobrecarga.

Además, yo personalmente uso 'where rownum < 1 ', ya que Oracle sabe de inmediato que todos los rownums han pasado eso, y no estoy seguro de si es lo suficientemente inteligente como para no intentar probar cada registro para' 1 = 0 '.

Además de la respuesta de skaffman -

use la siguiente consulta en Oracle:

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

para acceder a su nombre de esquema actual si tiene restricciones para hacerlo en Java.

Este es el comportamiento exigido por la API JDBC: pasar nulos como primer y segundo parámetro a getColumns significa que ni el nombre del catálogo ni el nombre del esquema se utilizan para limitar la búsqueda. Enlace a la documentación . Es cierto que algunos otros controladores JDBC tienen un comportamiento diferente de forma predeterminada (por ejemplo, el conector J de MySQL se restringe por defecto al catálogo actual), pero esto no es estándar y está documentado como tal

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top