MS-SQL 存储过程不适用于空参数

MS-SQL Stored Procedure doesn't work with empty params

我有一个包含输入 'name' 和 'phone' 的表单。

当它们有值时,一切正常:使用存储过程将记录插入数据库,spFoo:

String sp = "spFoo 'test name','test phone'";
OdbcCommand command = new OdbcCommand(sp, connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
Response.Write(command.ExecuteNonQuery().ToString());

但是当它们没有值时,我在应用程序中得到 -1 作为响应:

String sp = "spFoo '',''";

我希望用户无需任何输入即可创建记录。

为什么这在 Management Studio 中有效,但在应用程序中却无效?

更新: 我在存储过程中的参数中添加了默认值,但没有用;我在代码中给出了空字符串 "NULL" 作为值,仍然没有成功。这是服务器设置还是不允许空变量的设置?

从代码调用存储过程时,应在命令中使用参数 属性。试试这个:

String sp = "spFoo";
command.Parameters.Add("@name", "test name");
command.Parameters.Add("@phone", "test phone");

正如 JimmyV 所说,您应该使用 command.Parameters.Add 方法来设置您的参数,只要未指定参数值就传入 null。要解决您对错误“过程或函数 'spFoo' 需要参数‘@name’,未提供”的评论,您还需要修改存储过程以在未提供参数时使用默认值(例如 null):

CREATE PROCEDURE MyStoredProcedure
    @foo int = null
AS
BEGIN
...
END

很抱歉没有在上面添加评论 post。声望不够!

您不应该像现在这样调用存储过程。您应该使用参数。您的代码容易受到 SQL 注入的影响。

从不对用户输入的值进行字符串连接。

你应该有一个类似的存储过程设置:

CREATE PROCEDURE spFoo
    @name varchar(50) = 'Jim', -- default
    @phone varchar(50) = null -- optional
AS
BEGIN
    SET NOCOUNT ON;

    -- INSERT STATEMENT

END
GO

然后在代码中提供参数:

string name = this.nameTextBox.Text;
string phone = this.phoneTextBox.Text;

if (string.IsNullOrWhiteSpace(name))
    name = null;
if (string.IsNullOrWhiteSpace(phone))
    phone = null;

SqlConnection connection = new SqlConnection(@"<connection string>");

using (SqlCommand command = connection.CreateCommand())
{
    command.CommandType = CommandType.StoredProcedure;

    // leave this as the stored procedure name only
    command.CommandText = "spFoo";

    // if name is null, then Jim gets passed (see stored procedure definition)
    // if phone is null, then null gets passed (see stored procedure definition)
    command.Parameters.AddWithValue("@name", name);
    command.Parameters.AddWithValue("@phone", phone);

    try
    {
        connection.Open();

        int result = command.ExecuteNonQuery();

        Console.WriteLine(result);
    }
    finally
    {
        if (connection.State != ConnectionState.Closed)
            connection.Close();
    }
}

我不确定您为什么使用 Odbc 命名空间对象,因为听起来您使用的是 MS-SQL。您应该使用 System.Data.SqlClient 命名空间中的对象。


您实际问题的答案很可能涉及执行类似于以下内容的脚本(不是存储过程):

DECLARE @RC int
DECLARE @name varchar(50)
DECLARE @phone varchar(50)

-- TODO: Set parameter values here.

EXECUTE @RC = spFoo
   @name,
   @phone
GO

不推荐。

您需要从存储过程中删除 SET NOCOUNT ON;

来自documentation

Stops the message that shows the count of the number of rows affected by a Transact-SQL statement or stored procedure from being returned as part of the result set.

正如其他人指出的那样,您也应该对查询进行参数化,但是 -1 是由 NOCOUNT 引起的 ON

编辑

我知道这不是你要问的,但要使用 ODBC 的参数化查询,你需要根据文档 here 使用 ? 作为序号占位符。例如:

using (OdbcConnection connection = new OdbcConnection(connectionString))
{
    string sp = "{call spFoo (?, ?)}";

    using (OdbcCommand command = new OdbcCommand(sp, connection))
    {
        command.CommandType = System.Data.CommandType.StoredProcedure;

        connection.Open();
        //the order here is important, the names are not!
        command.Parameters.Add("@name", OdbcType.VarChar).Value = "test name";
        command.Parameters.Add("@phone", OdbcType.VarChar).Value = "test phone";

        Console.WriteLine(command.ExecuteNonQuery().ToString());
    }
}