【问题标题】:stored procedure always taking first parameter from the code存储过程总是从代码中获取第一个参数
【发布时间】:2013-10-21 16:50:02
【问题描述】:

我有一个这样的存储过程:

ALTER PROCEDURE [dbo].[T_TransactionSummary]  
 @locations nvarchar
AS
    BEGIN 
..............
.............
AND (Location_tbl.Locid IN (@locations))

我的 locid 字段是整数 这个 locid 来自我的列表框。如果我选​​择一个项目 1 locid 将会出现。如果我选​​择 2 项目 2 locid 将会出现.. 我有一个 ListBox 填充 @locations 参数(一个整数),我把我的列表框值像这样

cnt = LSTlocations.SelectedItems.Count
 Dim list As New List(Of Integer)
        Dim locid As Integer
        If cnt > 0 Then
            For i = 0 To cnt - 1
                Dim locationanme As String = LSTlocations.SelectedItems(i).ToString
                locid = RecordID("Locid", "Location_tbl", "LocName", locationanme)
                list.Add(locid)
            Next
End If
 Dim da As New SqlDataAdapter
        Dim ds As New DataSet
        Dim cmd23 As New SqlCommand("T_TransactionSummary", con.connect)
        cmd23.CommandType = CommandType.StoredProcedure
        cmd23.Parameters.Add("@locations", SqlDbType.Int).Value = String.Join(",", list)
        da.SelectCommand = cmd23
        da.Fill(ds)  

现在我来自列表框的 locationid 仅传递给存储过程 1、2、3。但存储过程总是取第一个值(我的意思是在这种情况下取​​ 1)。

【问题讨论】:

  • 您是否先进行了任何简单的调试?喜欢PRINT @locations;
  • 不,先生...为什么我必须这样做?
  • 因为在这种情况下,它会显示您传递的值被截断。

标签: sql-server vb.net


【解决方案1】:

首先,you absolutely need to define a length for your parameter...您当前拥有的是一个在第一个字符处被截断的字符串。

DECLARE @locations NVARCHAR;
SET @locations = '1,2,3';
SELECT @locations;

结果:

1

你需要说

@locations VARCHAR(MAX)

您不需要NVARCHAR 来存储以逗号分隔的整数列表。 (我假设您可能有一长串整数,但也许 MAX 可能是 8000。)

然后,您不能说 IN (@locations) - 这将无法正常工作,或者您将收到一条关于将 '1,2,3...' 转换为 int 的错误消息,或者它只是找不到值 - 与整个字符串,而不是集合。因此,您可以使用动态 SQL 来执行此操作,例如

SET @sql = @sql + ' WHERE locations IN (' + @locations + ') ...;';

但这充满了各种其他问题,包括可维护性和暴露于 SQL 注入。我强烈推荐使用表值参数。基本上你创建一个像这样的类型:

CREATE TYPE dbo.Integers AS TABLE(Item INT PRIMARY KEY);

那你这样使用参数:

@locations dbo.Integers READONLY

你可以说:

WHERE EXISTS (SELECT 1 FROM @locations WHERE Item = Location_tbl.Locid)

在您的 VB.Net 代码中,您将列表框选择填充到 DataTable(而不是 int 或字符串)中,并使用 SqlDbType.Structured 将 DataTable 作为参数传递。我这里有一些例子,但它们是 C#:

http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql

还有plenty of documentation on TVPs on MSDN

【讨论】:

  • 先生..我要改变什么..?
  • @user2878851 我想我在这里给出了非常全面和有用的说明。
  • @AaronBertrand:我同意。你的答案看起来很完整。
  • 先生我先执行:CREATE TYPE dbo.Integers AS TABLE(Item INT PRIMARY KEY);然后我将“@locations dbo.Integers READONLY”添加到我的 sp.but 得到错误必须声明标量变量“@locations”。
  • @user2878851 这不是“为我编写所有代码”论坛。尤其是当您一开始只包含非常简短的原始代码段时。你看到我如何改变@locations 变量的使用了吗?也许我应该给它取个不同的名字?您是否查看过我提供的任何链接以使用我的答案来帮助您了解如何使用这些技术?
【解决方案2】:

以下是第一个问题。

cmd23.Parameters.Add("@locations", SqlDbType.Int).Value = String.Join(",", list)

您将 @locations 参数添加为 int。当您将值分配给它时,VB 会将您的字符串转换为 int。这意味着"1,2,3,4" 将变为"1"

将其更改为 SqlDbType.VarChar


至于第二个,我不完全确定你能做到这一点:

AND (Location_tbl.Locid IN (@locations))

您可能希望改为查看表值参数。

【讨论】:

  • @user2878851:看看 Aaron 的回答。他告诉您将 sp 参数更改为 @locations dbo.Integers READONLY 的部分是 TVP。
  • 我刚刚在我的存储过程中给出了这样的:@locations integer readonly..现在我收到错误:参数“@locations”不能被声明为 READONLY,因为它不是表值参数.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-21
  • 2018-03-04
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 2018-09-18
相关资源
最近更新 更多