java - JDBC DatabaseMetaData.getColumns() devuelve columnas duplicadas
database-metadata (5)
Además de la respuesta de Skaffman -
Utilice la siguiente consulta en Oracle:
select sys_context( ''userenv'', ''current_schema'' ) from dual;
para acceder a su nombre de esquema actual si está restringido a hacerlo en Java.
Estoy ocupado en un pedazo 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 el ResultSet contenía un conjunto duplicado de todas las columnas, es decir, cada columna se devolvía dos veces. Aquí está la salida que tengo:
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 probado este código con varias tablas diferentes en mi base de datos y algunas funcionan bien, mientras que otras muestran este extraño comportamiento.
¿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 las columnas. Puedes 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 , deberías usar getColumnLabel () en lugar de getColumnName ().
En Oracle, Connection.getMetaData()
devuelve metadatos para toda la base de datos, no solo el esquema al que está conectado. Entonces, cuando proporciona null
como los dos primeros argumentos a meta.getColumns()
, no está filtrando los resultados solo para su esquema.
meta.getColumns()
proporcionar el nombre del esquema de Oracle a uno de los dos primeros parámetros de meta.getColumns()
, probablemente el segundo, por ejemplo
meta.getColumns(null, "myuser", "EMPLOYEES", null);
Es un poco irritante tener que hacer esto, pero así es como la gente de Oracle decidió implementar su controlador JDBC.
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 ''donde 1 = 0'', que usted no tiene. Esto es importante porque si lo deja apagado, entonces Oracle intentará devolver la tabla ENTERO. Y si no retira todos los registros, oracle los mantendrá a la espera de que los revise. Agregando que la cláusula where aún le da los metadatos, pero sin ninguna sobrecarga.
Además, personalmente uso ''where rownum <1'', ya que oracle sabe de inmediato que todos los rownums han superado eso, y no estoy seguro de que sea lo suficientemente inteligente como para no probar y probar cada registro para ''1 = 0''.
Este es el comportamiento requerido por la API de JDBC: pasar nulos como primer y segundo parámetro a getColumns significa que ni el nombre de catálogo ni el nombre de 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 manera predeterminada (por ejemplo, el ConnectorJ de MySQL se restringe de manera predeterminada al catálogo actual), pero esto no es estándar y está documentado como tal
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és haciendo, esto puede ser más conveniente. tablename
puede ser cualquier cosa que pueda seleccionar, no tiene que entender correctamente el caso ni preocuparse por el esquema en el que se encuentra.