java - salida - El parámetro @x no se definió para el procedimiento almacenado... con MS_SQL JDBC
procedimiento almacenado sql server ejemplo (1)
Estoy tratando de ejecutar un procedimiento almacenado utilizando SQL Server JDBC en un método:
//Connection connection, String sp_name, Map<String, Object>params input to the method
DatabaseMetaData dbMetaData = connection.getMetaData();
HashMap<String, Integer> paramInfo = new HashMap<String, Integer>();
if (dbMetaData != null)
{
ResultSet rs = dbMetaData.getProcedureColumns (null, null, sp_name.toUpperCase(), "%");
while (rs.next())
paramInfo.put(rs.getString(4), rs.getInt(6));
rs.close();
}
String call = "{ call " + sp_name + " ( ";
for (int i = 0; i < paramInfo.size(); i ++)
call += "?,";
if (paramInfo.size() > 0)
call = call.substring(0, call.length() - 1);
call += " ) }";
CallableStatement st = connection.prepareCall (call);
for (String paramName: paramInfo.keySet()){
int paramType = paramInfo.get(paramName);
System.out.println("paramName="+paramName);
System.out.println("paramTYpe="+paramType);
Object paramVal = params.get(paramName);
st.setInt(paramName, Integer.parseInt(((String)paramVal))); //All stored proc parameters are of type int
}
Supongamos que el nombre del procedimiento almacenado es ABC
y el parámetro es @a
. Ahora DatabaseMetaData
devuelve el nombre de la columna @a
pero la configuración de st.setInt("@a",0)
devuelve el siguiente error:
com.microsoft.sqlserver.jdbc.SQLServerException: el parámetro @a no se definió para el procedimiento almacenado ABC.
En cambio, probé esto: st.setInt("a",0)
y se ejecutó perfectamente.
Ahora el problema es que tengo que establecer los parámetros dinámicamente ya que tengo demasiados procedimientos almacenados y demasiados parámetros, pero jdbc está dando error.
Editar 1:
Como mencioné en una respuesta que mi pregunta es un duplicado de: Parámetros con nombre en JDBC , me gustaría explicar que el problema aquí no se llama parámetros o posicionales, sino que se trata de que JDBC no maneje los parámetros del servidor SQL propiamente o Estoy cometiendo un error al invocarlo.
Actualización 2017-10-07: se ha aceptado la solicitud de fusión para solucionar este problema , por lo que ya no debería ser un problema con las versiones 6.3.4 y posteriores.
Sí, es una incoherencia desafortunada que para mssql-jdbc los nombres de parámetros devueltos por DatabaseMetaData#getProcedureColumns
no coincidan con los nombres aceptados por CallableStatement#setInt
et. Alabama. . Si considera que se trata de un error, debe crear un problema en GitHub y quizás se solucione en una versión futura.
Mientras tanto, sin embargo, tendrás que evitarlo. Entonces, en lugar de un código como este ...
ResultSet rs = connection.getMetaData().getProcedureColumns(null, "dbo", "MenuPlanner", null);
while (rs.next()) {
if (rs.getShort("COLUMN_TYPE") == DatabaseMetaData.procedureColumnIn) {
String inParamName = rs.getString("COLUMN_NAME");
System.out.println(inParamName);
}
}
... que produce ...
@person
@food
... necesitarás usar un código como este ...
boolean isMssqlJdbc = connection.getClass().getName().equals(
"com.microsoft.sqlserver.jdbc.SQLServerConnection");
ResultSet rs = connection.getMetaData().getProcedureColumns(null, "dbo", "MenuPlanner", null);
while (rs.next()) {
if (rs.getShort("COLUMN_TYPE") == DatabaseMetaData.procedureColumnIn) {
String inParamName = rs.getString("COLUMN_NAME");
if (isMssqlJdbc && inParamName.startsWith("@")) {
inParamName = inParamName.substring(1, inParamName.length());
}
System.out.println(inParamName);
}
}
... que produce ...
person
food