如何使用相同的SqlConnection对象在多个SqlCommands中声明和使用T-SQL变量来执行多个插入?

Tri*_*nko 2 .net variables scope sql-server-2005 sqlcommand

我想加载一个记录列表给出一个可能很长的用户名列表(从一个到几千个用户名).忽略如何选择名称,并假设无法从数据库中的任何现有数据确定这些名称.这适用于SQL Server 2005.

我特别想避免在where子句中使用带有数千个表达式单个select语句,这会导致SqlCommand对象的命令文本过长(例如...where n='bob000001' or n='bob000002' or ... or n='bob003000').听起来合理吗?

我决定通过使用用户名填充一个简单的表变量来执行选择,然后使用用户数据在表变量和表之间执行select/join.

所以,我需要做的第一件事是填充表变量.我有一些问题:

  • SQL Server 2008之前的T-SQL语法很简单,只需在单个语句中将多行插入表中,就需要多次选择和联合all.
  • 我没有使用SS2005的详细语法,甚至SQL Server 2008中提供的简洁语法,而是完全避免使用冗长的命令文本,只使用单个连接上的多个命令.
  • 在一个SqlCommand中声明一个表变量,当我尝试在后续的SqlCommands中使用它时,会产生"必须声明标量变量"错误.
  • 以任何方式涉及存储过程可能仍然涉及传递大量字符串,或者可能阻止变量持久存储在存储过程的范围之外.假设创建存储过程不是一种选择.

第三点是我现在要解决的问题.我已经看过人们(声称)成功声明并在单个SqlCommand中使用变量而没有错误的示例.使用多个SqlCommand实例时如何实现?我读到变量将持续存在于多个命令之间的单个连接.涉及交易可能会以某种方式帮助吗?

最后,请记住我不想使用临时表; 这样做会提供一个简单的解决方案,但它也避免了我要问的有关变量和多个SqlCommands的问题; 但是,如果你真的认为这是最好的选择,请随意说出来.

这是一个代码片段,显示正在发生的事情:

public static List<Student> Load( SqlConnection conn, List<StudentID> usernames )
{
    //Create table variable
    SqlCommand  command = new SqlCommand( "declare @s table (id varchar(30))", conn );
    command.ExecuteNonQuery();

    //Populate a table variable with the usernames to load
    command = new SqlCommand( "insert into @s (id) values (@p)", conn );
    command.Parameters.Add( "@p", SqlDbType.VarChar );
    int len = usernames.Count;
    for (int i = 0; i < len; i++)
    {
        command.Parameters["@p"].Value = usernames[i].ToString();
        command.ExecuteNonQuery(); //ERROR: must declare scalar variable @s
    }

    //Select all students listed in the table variable
    command = new SqlCommand( "select StudentID, FName, LName, [etc.] from Student inner join @s on StudentID = @s.id order by StudentID", conn );

    //Execute the query to get the student info from the database.
    List<Student> students = new List<Student>()
    using(SqlDataReader reader = command.ExecuteReader())
    {
        //code to load results and populate students list
    }
    return students;
}
Run Code Online (Sandbox Code Playgroud)

注意:我知道涉及参数的SqlCommand在内部调用存储过程,这通常会阻止跨多个SqlCommands的持久化变量,但是声明表变量的第一个查询不涉及参数(即没有引用command.Parameters.添加了AddWithValue,因此它应该在以后可以调用存储过程的命令的范围内.

编辑:要使用临时表,只需将@s 更改为#s和declare @s表"到create table #s,这很好.人们可能还想在最后删除临时表,但这不是必需的.

gbn*_*gbn 5

使用临时表,该表在会话/连接期间持续存在(多次调用).表变量只有批处理的范围,基本上是一个调用.