我想加载一个可能很长的用户名列表(从一个到数千个用户名)的记录列表。忽略名称是如何选择的,并假设它们无法从数据库中的任何现有数据中确定。这适用于 SQL Server 2005。
我特别想避免在 where 子句中使用带有数千个表达式的单个 select 语句,这会导致 SqlCommand 对象的命令文本过长(例如...where n='bob000001' or n='bob000002' or ... or n='bob003000'
)。听起来合理吗?
我决定通过使用用户名填充一个简单的表变量来执行选择,然后在表变量和带有用户数据的表之间执行选择/连接。
所以,我需要做的第一件事是填充表变量。我这里有一些问题:
- SQL Server 2008 之前的 T-SQL 语法对于在单个语句中将多行插入表中是冗长的,需要类似multiple selects 和 union alls 之类的东西。
- 我没有使用 SS2005 的冗长语法,甚至 SQL Server 2008 中可用的简洁语法,而是完全避免冗长的命令文本,而只是在单个连接上使用多个命令。
- 在一个 SqlCommand 中声明表变量,当我尝试在后续 SqlCommand 中使用它时会产生“必须声明标量变量”错误。
- 以任何方式涉及存储过程仍可能涉及传递巨大的字符串,或者可能会阻止变量在存储过程范围之外持续存在。假设创建存储过程不是一种选择。
第三点确实是我现在要解决的问题。我已经看到人们(声称)在单个 SqlCommand 中成功声明和使用变量而没有错误的示例。使用多个 SqlCommand 实例时如何实现这一点?我读到变量将针对多个命令的单个连接持续存在。可能以某种方式涉及交易帮助?
最后,请记住,我不想使用临时表;这样做会提供一个简单的解决方案,但它也避免了我提出的关于变量和多个 SqlCommand 的问题;但是,如果您真的认为这是最好的选择,请随意说出来。
这是一个显示正在发生的事情的代码片段:
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;
}
注意:我知道涉及参数的 SqlCommand 在内部调用存储过程,这通常会阻止跨多个 SqlCommands 持久化变量,但声明表变量的第一个查询不涉及参数(即不引用 command.Parameters。 AddWithValue 已生成),因此它应该在以后可能调用存储过程的命令的范围内。
编辑:要使用临时表,只需将@
s 更改为#
s 并将declare @
s table" 更改为create table #
s,这很好。人们可能还想在最后删除临时表,但这不是必需的。