【问题标题】:MS-SQL Stored Procedure doesn't work with empty paramsMS-SQL 存储过程不适用于空参数
【发布时间】:2015-01-13 17:44:25
【问题描述】:

我有一个输入“姓名”和“电话”的表单。

当它们有值时,一切正常:使用存储过程 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());
  • 适用于应用程序
  • 在 Mgmt Studio 上工作

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

String sp = "spFoo '',''";
  • 在应用程序中不起作用 (-1)
  • 在 Mgmt Studio 上工作

我希望用户能够在没有任何输入的情况下创建记录。

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

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

【问题讨论】:

  • 修改sp,使param作为可选参数,然后直接从代码中调用sp
  • 因为您将命令文本设置为过程的名称。然后你需要为每个参数添加参数到你的命令中。
  • 程序中有什么?表结构如何?首先,如果变量的值未通过过程,您是否使用默认值作为 nulll。并且在插入的情况下,您的表是否允许 NULL 值。
  • 你的存储过程中有SET NOCOUNT ON;吗?如果是这样,您应该删除它,因为它会阻止 SQL Server 从 SP 返回受影响的行数。
  • 就是这样!我删除了它并开始恢复 1。当我检查数据库时,我有一堆空记录。我想服务器需要一段时间才能告诉我它有新记录。把它作为一个答案,我会给你信用,@petelids。

标签: c# sql-server


【解决方案1】:

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

来自documentation

停止显示受 Transact-SQL 语句或存储过程影响的行数的消息作为结果集的一部分返回。

正如其他人指出的那样,您也应该参数化您的查询,但 -1 是由 NOCOUNTON 引起的。

编辑

我意识到这不是您要的,而是要使用带有 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());
    }
}

【讨论】:

  • 通过参数添加变量对我不起作用,因为我使用的是 OdbcCommand。我正在使用 Odbc,因为这是您可以使用 DSN 的唯一方法。我得到的最接近的是使用问号而不是@var_name,即使这样也没有用。我不得不恢复直接在 commandText 中添加参数。
【解决方案2】:

当您从代码中调用存储过程时,您应该使用命令的Parameters 属性。试试这个:

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

【讨论】:

  • 更糟糕的是:过程或函数“spFoo”需要参数“@name”,但未提供。
  • @TravisHeeter 那是因为您需要在存储过程中添加一个名为 @name 的参数。
  • 我的存储过程:INSERT INTO spFoo (name,phone) VALUES (@name,@phone)。不过,我克服了“spFoo 预期”错误,但仍然得到 -1。
  • @TravisHeeter 我希望你的表名和你的存储过程名不一样。
【解决方案3】:

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

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

很抱歉没有在上面的帖子中添加评论。声望不够!

【讨论】:

  • 都试过了,还是不行。我觉得每个人都在谈论我“应该”做什么而忽略了真正的问题。
【解决方案4】:

您不应该像现在这样调用存储过程。你应该使用参数。您的代码容易受到 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

不推荐。

【讨论】:

  • 好的,我重写了我的整个函数和存储过程,但我仍然得到-1。我现在有你在这里写的东西(更长的版本,不是脚本)。编辑,虽然我还没有尝试 SqlClient。我认为您不能将 dsn 与 SqlClient 一起使用。
  • 试过SqlClient,果然不能用dsn和SqlClient。
  • 如果您想知道,您不能在 odbc 中以相同的方式使用参数:stackoverflow.com/questions/18082840/…
猜你喜欢
  • 2022-08-10
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
  • 2016-10-16
  • 2014-05-16
  • 1970-01-01
  • 2011-01-23
  • 2014-03-28
相关资源
最近更新 更多