【问题标题】:Must declare scalar variable when passing bool传递 bool 时必须声明标量变量
【发布时间】:2019-06-04 12:54:46
【问题描述】:

SQL Server 是 2014。Visual Studio 2017。

我正在尝试将 3 个参数传递给 SQL Server,但收到此错误:

System.Data.SqlClient.SqlException: '必须声明标量变量“@Title1Item”。'

我已经包含了 C# 和 SQL Server 端代码。谁能告诉我我做错了什么?

public DataTable GetInventoryByAssetDescription (string Desc, string DispositionText, bool Title1Item) {

    DataTable myRecords = new DataTable(); 
    using (SqlConnection cn = new SqlConnection (ConnectionString)) {

    // Specify which stored procedure to use and add a parameter.
    SqlCommand cmd = new SqlCommand ("GetInventoryByAssetDescription", cn);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue ("@SearchString", Desc);
    cmd.Parameters.AddWithValue ("@DispositionText", DispositionText);
    cmd.Parameters.AddWithValue ("@Title1Item", Title1Item);

    SqlDataAdapter da = new SqlDataAdapter (cmd);
    cn.Open();
    da.Fill (myRecords);
}

ALTER PROCEDURE [dbo].[GetInventoryByAssetDescription] (
    @SearchString varchar(30),
    @DispositionText varchar(200),
    @Title1Item bit
)

我希望将 3 个参数传递给存储过程,但在 da.fill (myRecords) 行上出现此错误:

System.Data.SqlClient.SqlException: '必须声明标量变量“@Title1Item”。'

编辑:很抱歉,伙计们。生锈的老程序员在这里。存储过程代码:

USE [Inventory]
GO
/****** Object:  StoredProcedure [dbo].[GetInventoryByAssetDescription]    Script Date: 6/4/2019 8:30:15 AM ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER PROCEDURE [dbo].[GetInventoryByAssetDescription]
      (
            @SearchString varchar(30),
            @DispositionText varchar(200),
            @Title1Item bit
      )  
AS
begin
    SET NOCOUNT ON
    declare @sql nvarchar (2000)

    select @SearchString=UPPER(@SearchString)
    set @sql = '   select in_eq_ID,
        in_eq_TagNumber as TagNumber,
        Title1Item,
        in_eq_AssetDescription as Description,
        in_eq_ExtendedDescription as ExtendedDescription,
        in_eq_SerialNumber as SerialNumber,
        in_eq_ValuationAmount as TotalValue,
        in_eq_CustodianName as Name,
        in_eq_ComplexBuilding as ShortLocation,
        in_eq_SubLocationCode as ShortRoomNumber,
        in_ca_Categories.in_ca_CategoryName as CategoryName,
        in_eq_DispositionDate as DispositionDate,
        DATEADD (dd, 0, DATEDIFF (dd, 0, in_eq_Equipment.in_eq_AcquisitionDate)) as AcquisitionDate
        from in_eq_Equipment
            LEFT JOIN in_ca_Categories ON in_eq_Equipment.in_eq_CategoryID_fk = in_ca_Categories.in_ca_CategoryID
            where @Title1Item = Title1Item
                AND upper (in_eq_AssetDescription) LIKE upper ('''+ @SearchString + ''')'

        set  @sql=@sql+'   ' + ISNULL(@DispositionText,' ')  + '  order by in_eq_AssetDescription'
        execute (@sql)
        return
end

【问题讨论】:

  • 你能不能把整个GetInventoryByAssetDescription程序贴上去,肯定不是这样
  • 看起来应该可以工作;随机问题 - DescDispositionText 是否可能是 null(而不是 "")?另外:您是否有可能在存储过程中做一些不平凡的事情,例如 EXEC / sp_executesql 这实际上是出现错误的事情?
  • Desc is "%1%" DispositionText is " and ((in_eq_DispositionDate is null) or (in_eq_DispositionDate = ''))" Title1Item = false
  • " and ((in_eq_DispositionDate is null) or (in_eq_DispositionDate = ''))" 建议您使用EXEC,这是 a: 几乎可以肯定是 SQL 注入漏洞,而 b: 几乎可以肯定是您看到这个的原因;你能发布GetInventoryByAssetDescription的完整代码吗 - 我认为问题是SP写得不好
  • 这就是除了return语句之外的整个方法:return myRecords; }

标签: c# sqlexception


【解决方案1】:

当您在 SQLServer 中使用数据类型 BIT 作为 SP 参数时,您必须从 C# 发送值 1 或 0 而不是 true 或 false,因此您必须将 bool 转换为 int(1 表示 true,0 表示 false)

例如

cmd.Parameters.AddWithValue ("@Title1Item", Title1Item ? 1 : 0);

cmd.Parameters.AddWithValue ("@Title1Item", (int)Title1Item);

【讨论】:

  • 更改代码时仍然出现同样的错误。
【解决方案2】:

对;问题是您的 SP,而不是 C# 代码。它不能以所写的方式工作。参数和局部变量不是“环境变量”——它们不会在 EXECEXECUTE 块内定义,因为它们不在其中的范围内。在某些情况中,sp_executesql 允许您通过声明它们并将它们添加为附加参数来传递参数/值,但在您的情况下,这不是一个好主意,因为从根本上说您正在做一些难以置信危险的事情,即连接输入以创建 SQL。您现在的存储过程是一个 SQL 注入漏洞,可用于以最小的努力接管您的服务器。如果您对自己的数据被盗并且数据库被破坏感到满意,您可以像对待其他人一样内联/连接@Title1Item,但是:这是一个可怕的想法,它会伤害您.

【讨论】:

  • 马克,在这样一个可怕的警告之后,我确实理解和欣赏,我不想问,但由于时间限制,我必须......我如何像我一样内联/连接#Title1Item其他人呢?我不太明白你在说什么。
  • 我想应该是这样的:set @sql=@sql+' ' + ISNULL (@Title1Item, '0') + ' and '
  • where /@Title1Item = Title1Item 这部分抛出异常 /@Title1Item 应该在引号之外,例如 where' + /@Title1Item + ' = Title1Item
  • 谢谢@OlegBondarenko,但不能在引号之外加上斜线,如下所示: where ' + /@Title1Item + ' = Title1Item
  • @OlegBondarenko,这似乎有效: where ' + convert(varchar(1), @Title1Item) + ' = Title1Item 我向所有人道歉......我在接近 20 年前编写了原始代码,而且我已经 7 年没有编码了。现在一切都变得非常模糊。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-03
  • 1970-01-01
  • 2013-07-03
  • 1970-01-01
相关资源
最近更新 更多