按参数列表筛选SQL查询

时间:2012-07-19 13:02:20

标签: c# sql sql-server performance sql-server-2008

我有一个查询,我想返回与值列表关联的所有行。你可以这么简单地写成:

select * from TableA where ColumnB in (1, 2, 3, 5)

我可以在C#中生成此查询并执行它。然而,这显然不太理想,因为它不使用参数,在尝试缓存查询计划时会受到影响,并且显然容易受到SQL注入攻击。

另一种方法是将其写为:

select * from TableA where ColumnB = @value

这可以通过C#执行多次,但这会导致N DB命中。

我能看到的唯一其他选择是创建一个临时表并以这种方式加入它,但是我没有看到这一点,因为它会更复杂并且受到与第一个选项相同的限制。 / p>

我正在使用SQL Server和OLDB,创建查询不是问题。我正在努力创造最有效的流程。

这三种方法中哪一种更有效?我错过了替代方案吗?

3 个答案:

答案 0 :(得分:4)

假设SQL Server 2008或更高版本,在SQL Server中创建一次表类型:

CREATE TYPE dbo.ColumnBValues AS TABLE
(
  ColumnB INT
);

然后是一个采用输入类型的存储过程:

CREATE PROCEDURE dbo.whatever
  @ColumnBValues dbo.ColumnBValues READONLY
AS
BEGIN
  SET NOCOUNT ON;

  SELECT A.* FROM dbo.TableA AS A
    INNER JOIN @ColumnBValues AS c
    ON A.ColumnB = c.ColumnB;
END
GO

现在在C#中,创建一个DataTable并将其作为参数传递给存储过程:

DataTable cbv = new DataTable();
cbv.Columns.Add(new DataColumn("ColumnB"));

// in a loop from a collection, presumably:
cbv.Rows.Add(someThing.someValue);

using (connectionObject)
{
    SqlCommand cmd        = new SqlCommand("dbo.whatever", connectionObject);
    cmd.CommandType       = CommandType.StoredProcedure;
    SqlParameter cbvParam = cmd.Parameters.AddWithValue("@ColumnBValues", cbv);
    cbvParam.SqlDbType    = SqlDbType.Structured;
    //cmd.Execute...;
}

(您可能希望使该类型更通用,我专门命名它以明确它正在做什么。)

答案 1 :(得分:2)

你也可以使用multiple resultsets并发送一个像这样的查询:

select * from TableA where ColumnB = @value0
select * from TableA where ColumnB = @value1
select * from TableA where ColumnB = @value2
...
select * from TableA where ColumnB = @valuen

单一电话中。 即使显然反直觉,它也会利用执行计划,并且在参数化方面是安全的。

答案 2 :(得分:0)

您可以轻松地写下这个:

String csvString = "1, 2, 3, 5"; // Built the list somehow, don't forget escaping
String query = "select * from TableA where ColumnB in (" + csvString + ")";

通过这种方式,性能不会降低,并且您可以在创建csvString时阻止 Sql Injection 简单地转义输入值。

顺便说一句,如果你使用 MS SQL 而不是标准SQL,你可以find alternative ways