Sql server 仅指定具有值的参数的调用存储过程

Sql server 仅指定具有值的参数的调用存储过程,sql-server,stored-procedures,jdbc,parameters,mssql-jdbc,Sql Server,Stored Procedures,Jdbc,Parameters,Mssql Jdbc,在SQL Server 2016的一个实例中,我有一个包含数十个参数的存储过程。例如: CREATE PROCEDURE spName ( @par1 INT = NULL, @par2 VARCHAR(10) = NULL, .... .... @par98 INT = NULL, @par99 INT = NULL, ) AS BEGIN .... .... END 我有一个用C#编写的客户机,它调用存储过程,

在SQL Server 2016的一个实例中,我有一个包含数十个参数的存储过程。例如:

CREATE PROCEDURE spName (
    @par1 INT = NULL,
    @par2 VARCHAR(10) = NULL,
        ....
        ....
    @par98 INT = NULL,
    @par99 INT = NULL,
) AS
BEGIN
    ....
    ....
END
我有一个用C#编写的客户机,它调用存储过程,只指定带值的参数。例:

SqlCommand cmd = new SqlCommand();

cmd.CommandText = "spName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = dbConn;

cmd.Parameters.Add(new SqlParameter("par1", "val1"));
cmd.Parameters.Add(new SqlParameter("par47", "val47"));

...

cmd.ExecuteNonQuery();
它工作得很好!因此,执行该过程,只有2个参数(par1和par47)有一个值。其他参数保持默认值(NULL)

我将使用MicrosoftJDBCDriver6.2在Java客户机上执行同样的操作。 我使用
List
指定参数,因此会创建一个包含两个parameterName-->parameterValue的列表。以下方法生成
PreparedStatement
对象:

private CallableStatement prepareStatement(String spName, Map<String, ?> parameters) throws SQLException {
    setupConnection();
    CallableStatement stmt = null;
    try {
        stmt = conn.prepareCall(getSpCallString(spName, parameters));
        if (parameters != null) {
            for (String parName : parameters.keySet())
                stmt.setObject(parName, parameters.get(parName));
        }
    } catch (SQLException e) {
        ApplicationLogging.severe("Cannot prepare callable statement", e);
        throw e;
    }
    return stmt;
}
我可以通过将调用命令的数量与存储过程的参数数量相同来解决这个问题,但是。。。我不知道每个存储过程的参数数量(以及它们的位置)! 在C#中,这是简单的解决方法,因为参数只分配了名称,所以参数的数量和顺序实际上是一个黑匣子

我可以在Java中以某种方式做到这一点吗?

这是mssql jdbc驱动程序中对
CallableStatement
命名参数支持的当前实现中的一个例子。尽管JDBC 4.2规范第13.3.2节指出

命名参数只能用于指定没有默认值的值

。。。我们似乎需要为每个可能的参数提供一个参数占位符,而且似乎没有办法为我们可能忽略的参数指定
DEFAULT

作为一种解决方法,我们可以使用这样的代码

// test data
Map<String, Object> paramItems = new HashMap<>();
paramItems.put("@person", "Gord");
paramItems.put("@food", "bacon");
paramItems.put("@helpings", 3);
//
ResultSet rs = executeStoredProcedureQuery(conn, "dbo.BreakfastSP", paramItems);
公共静态结果集executeStoredProcedureQuery(
连接连接、字符串spName、映射参数项)
抛出SQLException{
StringBuffer sqlBuf=新的StringBuffer(“EXEC”);
sqlBuf.append(spName);
int paramCount=1;
for(字符串paramName:paramItems.keySet()){
sqlBuf.append(
(paramCount++>1?,“:”)+
(paramName.startsWith(“@”)?:“@”)+paramName+“=?”;
}
字符串sql=sqlBuf.toString();
myLogger.log(Level.INFO,sql);
//例如,EXEC dbo.breakfasts sp@helpings=?,@person=?,@food=?
PreparedStatement ps=conn.prepareStatement(sql);
参数计数=1;
for(字符串paramName:paramItems.keySet()){
ps.setObject(paramCount++,paramItems.get(paramName));
}
返回ps.executeQuery();
}
我们可以这样称呼它

// test data
Map<String, Object> paramItems = new HashMap<>();
paramItems.put("@person", "Gord");
paramItems.put("@food", "bacon");
paramItems.put("@helpings", 3);
//
ResultSet rs = executeStoredProcedureQuery(conn, "dbo.BreakfastSP", paramItems);
//测试数据
Map paramItems=新建HashMap();
参数项。put(“@person”,“Gord”);
把(“@食物”,“培根”);
参数项。放置(“@helpings”,3);
//
结果集rs=ExecuteStoreProcedureQuery(连接“dbo.BreakfastSP”,参数项);

什么是价值化参数?我不熟悉这个术语,我指的是我给存储过程的参数(有一个值)。其他参数不会传递,因此它们会保留其默认值(NULL)。如果不生成SQL Server特定的存储过程调用并显式为命名参数赋值,则不能传递。我想您的意思是要使用可选参数?您必须使用命名参数才能工作,并且必须在过程定义中指定一个默认值(可以为NULL)。但是,您怎么可能不知道存储过程中有多少个参数呢?如果你不知道参数,也许你应该考虑不要调用这个过程。或者至少花一点时间看看程序,这样你就知道你在做什么了。嗨,肖恩。我有一个存储过程,它通过许多参数提取数据过滤。然后我有各种各样的用户界面。它们都调用相同的存储过程,但每个存储过程都有不同的参数传递给存储过程(参数的子集)。当处理客户端请求时,只有来自调用视图的参数被传递到存储过程,而不是全部。谢谢Gord。我还认为这是MS Jdbs驱动程序的一个“bug”或缺失的特性。