Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用逗号分隔的类似数组的字符串执行存储过程_C#_.net_Sql_Tsql_Sql Server 2008 R2 - Fatal编程技术网

C# 使用逗号分隔的类似数组的字符串执行存储过程

C# 使用逗号分隔的类似数组的字符串执行存储过程,c#,.net,sql,tsql,sql-server-2008-r2,C#,.net,Sql,Tsql,Sql Server 2008 R2,可能重复: 我想编写一个存储过程,在表上执行select,并且需要一个varcharmax类型的输入变量 我想发送一组以分隔的值作为输入参数,例如 'Jack','Jane','Joe' 然后获取包含其中一个名称的行 在SQL中,代码是 Select * from Personnel where Name in ('Jack','Joe','Jane'); 现在我想在我的C应用程序中有一个变量,比如strNames,然后像这样填充它 string strNames = "'Jack',

可能重复:

我想编写一个存储过程,在表上执行select,并且需要一个varcharmax类型的输入变量

我想发送一组以分隔的值作为输入参数,例如

'Jack','Jane','Joe'
然后获取包含其中一个名称的行

在SQL中,代码是

Select * from Personnel where Name in ('Jack','Joe','Jane');  
现在我想在我的C应用程序中有一个变量,比如strNames,然后像这样填充它

string strNames = "'Jack','Joe','Jane'";
并将此变量发送到SP并执行它。差不多

Select * from Personnel where Name in (''Jack','Joe','Jane'') -- this is wrong
但是我如何告诉SQLServer运行这样的命令呢


我需要实现这一点,我知道这是可能的,请给我线索。

我想您需要Sql Server中的Split函数将逗号分隔的字符串拆分为表。请参考这些链接

您可以使用从表中选择数据

Select * from 
Personnel where 
  Name in (select items from dbo.Split ('Jack,Joe,Jane',','))

首先,将单个名称传递给存储过程时,不需要引用它们

using (SqlCommand cmd = new SqlCommand("MyStoredProc", conn))
{
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@longFilter", "Jack,Jill,Joe");

    using (SqlDataReader reader = cmd.ExecuteReader())
    {
        ...
    }
}
然后,在存储过程中,您可以使用简单的文本函数和一个临时表,如下所示,在逗号处拆分字符串,并为字符串的每个部分创建一个临时表条目:

DECLARE @temp AS TABLE (Name NVARCHAR(255))

IF ISNULL(@longFilter, '') <> ''
BEGIN
    DECLARE @s NVARCHAR(max)
    WHILE LEN(@longFilter) > 0
    BEGIN
        IF CHARINDEX(',', @longFilter) > 0
        BEGIN
            SET @s = LTRIM(RTRIM(SUBSTRING(@longFilter, 1, CHARINDEX(',', @longFilter) - 1)))
            SET @longFilter = SUBSTRING(@longFilter, CHARINDEX(',', @longFilter) + 1, LEN(@longFilter))
        END ELSE
        BEGIN
            SET @s = LTRIM(RTRIM(@longFilter))
            SET @longFilter= ''
        END

        -- This was missing until 20140522
        INSERT INTO @temp (Name) VALUES (@s)
    END
END

您只需检查字符串中是否包含名称。请注意结尾开头的逗号,以确保与全名匹配

string strNames = ",Jack,Joe,Jane,";
SQL成为

select * from Personnel where PATINDEX('%,' + Name + ',%', @strNames) > 0
请参阅您可以使用的

基本上,您可以在过程中插入一个值列表作为参数,并将其用作表,类似于

Select * from Personnel 
  where Name in (select name from @NamesTable).
现在,具体情况如何

若要使用表值参数,必须在sql server中使用预定义参数的类型

create type NamesTable as table (Name varchar(50))
然后,可以将定义的类型用作过程中的参数

create procedure getPersonnelList
  @NamesTable NamesTable readonly
as
begin
  select * from personnel
    where Name in (select Name from @NamesTable)
end
你可以在行动中看到这一点

在C端,您需要创建参数。如果集合中有名称并生成字符串,则可以使用该名称生成参数,如果它们是逗号分隔的字符串,则可以使用快速字符串。拆分可以解决这一问题。因为我不知道你的具体情况,我假设你有一个名字列表。您需要将其转换为一个表值参数,然后发送到过程中,方法如下:

DataTable tvparameter = new DataTable();
tvparameter.Columns.Add("Name", typeof(string));
foreach (string name in names)
{
  tvparameter.Rows.Add(name);
}
您可以在中找到有关如何在C代码中生成TVP的更多信息

现在只需要将该参数发送到过程,就这样。这是一个完整的控制台程序,它执行该过程并输出结果

List<string> names = new List<string> { "Joe", "Jane", "Jack" };

using (SqlConnection cnn = new SqlConnection("..."))
{
  cnn.Open();
  using (SqlCommand cmd = new SqlCommand("getPersonnelList", cnn))
  {
    cmd.CommandType = CommandType.StoredProcedure;

    DataTable tvparameter = new DataTable();
    tvparameter.Columns.Add("Name", typeof(string));
    foreach (string name in names)
    {
      tvparameter.Rows.Add(name);
    }

    cmd.Parameters.AddWithValue("@NamesTable", tvparameter);

    using (SqlDataReader dr = cmd.ExecuteReader())
    {
      while (dr.Read())
      {
        Console.WriteLine("{0} - {1}", dr["ID"], dr["Name"]);
      }
    }
  }
}

例如,是否可以将此字符串Select*从表1发送到存储过程,然后sp将其作为命令执行?我想让sql执行一个字符串。是的,这是可能的,但我从来没有这样做过。哎呀,因为它易受攻击?还是其他原因?我很好奇脆弱是一回事。您还失去了.NET framework提供的所有舒适感,例如,参数总是以正确的格式传递给查询,等等。想想i18关于日期或浮点值的问题。另外,如果要将语句发送到存储过程,也可以立即在应用程序中执行它—有什么区别?Mahdi。您可以使用sp_executesql命令实现这一点:它确实有自己的位置。但是你需要非常谨慎地使用它。我主要关心的是确保您没有使用用户输入来构建sql命令,因此也没有使用sql-injection。我所知道的用于此目的的最佳功能是如何工作?看起来longFilter值从未存储在temp表中。是否缺少一些SQL代码?我遗漏了一些明显的东西吗?事实上,你是对的,有趣的是,以前没有人注意到这一点——临时表中的实际插入丢失了。我加了一句评论。谢谢你指出这一点!
List<string> names = new List<string> { "Joe", "Jane", "Jack" };

using (SqlConnection cnn = new SqlConnection("..."))
{
  cnn.Open();
  using (SqlCommand cmd = new SqlCommand("getPersonnelList", cnn))
  {
    cmd.CommandType = CommandType.StoredProcedure;

    DataTable tvparameter = new DataTable();
    tvparameter.Columns.Add("Name", typeof(string));
    foreach (string name in names)
    {
      tvparameter.Rows.Add(name);
    }

    cmd.Parameters.AddWithValue("@NamesTable", tvparameter);

    using (SqlDataReader dr = cmd.ExecuteReader())
    {
      while (dr.Read())
      {
        Console.WriteLine("{0} - {1}", dr["ID"], dr["Name"]);
      }
    }
  }
}