如何使用“WHERE [columnname] IN [values]”语句运行包含字符串值列表的 SQL 查询ASP.NET 中的格式?

发布于 2024-10-21 19:52:43 字数 904 浏览 3 评论 0原文

我有一个在 ASP.NET 页面中运行的 SQL 查询。最终解析的 SQL 需要包含 WHERE [columnname] IN [values] 格式的字符串值列表。例如,最终查询可能如下所示:

SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN ('ABC','DEF','GHI','JKL', /* etc */);

但是,WHERE 子句中的字符串值需要是动态的。通常我使用参数化查询来使我的代码方便且安全,因此从概念上讲我想做这样的事情:

String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN (@ProductCodes)";
cmd.Parameters.Add("@ProductCodes", productCodes);

但是,.NET 中似乎不存在这种功能。我应该如何实施这个?我可以在数组上使用 foreach 循环,并使用单个值作为每个值的参数运行查询,但数组中可能有一百个左右不同的值,而且单独查询它们似乎效率非常低。

我读过另一个问题,其中有人提出了强类型 int 参数的解决方案,但是当与字符串值一起使用时,该方法会让我对 SQL 注入感到紧张,特别是因为客户端很可能能够影响输入值。

您将如何实现此查询功能?

编辑数据库详细信息

数据库是 SQL Server 2005。很抱歉忘记提及这一点。

I have a SQL query I'm running in an ASP.NET page. The final parsed SQL needs to contain a list of string values in the WHERE [columnname] IN [values] format. For example, the final query might look something like this:

SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN ('ABC','DEF','GHI','JKL', /* etc */);

However, the string values in the WHERE clause need to be dynamic. Normally I use parametrized queries to make my code convenient and safe, so conceptually I'd like to do something like this:

String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN (@ProductCodes)";
cmd.Parameters.Add("@ProductCodes", productCodes);

However, this sort of functionality doesn't appear to exist in .NET. How should I go about implementing this? I could use a foreach loop on the array and run a query with a single value as a parameter for each value, but there could potentially be a hundred or so different values in the array and it seems like querying them separately would be very inefficient.

I've read another question where someone suggested a solution for strongly-typed int parameters, but that method would make me nervous about SQL injection when used with String values, especially since the client may very well be able to influence the input values.

How would you implement this query functionality?

EDIT with DB Details:

The database is SQL Server 2005. Sorry for forgetting to mention that.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挽清梦 2024-10-28 19:52:43

创建基本 sql 语句作为一种格式,并动态添加参数,然后在循环中设置值。

String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
string sqlFormat = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN ({0})";
var @params = productCodes.Select((id, index) => String.Format("@id{0}", index)).ToArray();
var sql = String.Format(sqlFormat, string.Join(",", @params));

using(var cmd = new DbCommand(sql))
{
    for (int i = 0; i < productCodes.Length; i++)
        cmd.Parameters.Add(new Parameter(@params[i], DbType.String, productCodes[i]));
    // execute query
}

Create your base sql statement as a format, and add the parameters dynamically, and then set the values in a loop.

String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
string sqlFormat = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN ({0})";
var @params = productCodes.Select((id, index) => String.Format("@id{0}", index)).ToArray();
var sql = String.Format(sqlFormat, string.Join(",", @params));

using(var cmd = new DbCommand(sql))
{
    for (int i = 0; i < productCodes.Length; i++)
        cmd.Parameters.Add(new Parameter(@params[i], DbType.String, productCodes[i]));
    // execute query
}
蓬勃野心 2024-10-28 19:52:43

只是一个想法:

String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN ("; 

for (int i=0;i<productCodes.Length;i++) {
  cmd.CommandText += "@" + productCodes[i] + ",";
  cmd.Parameters.Add("@" + productCodes[i], productCodes[i]);
}
cmd.CommandText = cmd.CommandText.SubString(0, cmd.CommandText.Length-1);
cmd.CommandText += ");"

可能不是最好的方法,但我想这就是我尝试的方法。

Just an idea:

String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN ("; 

for (int i=0;i<productCodes.Length;i++) {
  cmd.CommandText += "@" + productCodes[i] + ",";
  cmd.Parameters.Add("@" + productCodes[i], productCodes[i]);
}
cmd.CommandText = cmd.CommandText.SubString(0, cmd.CommandText.Length-1);
cmd.CommandText += ");"

Probably not the best way, but I guess this is how I would try it.

叹沉浮 2024-10-28 19:52:43

根据记录,“不单独”查询数组中的大约一百个值也可能效率低下(尽管不像与 SQL Server 进行一百次左右的往返那样低效)。但是,参数化查询会有所帮助,因为您可以准备相同的查询并执行它多次。存储过程可能会更好。

您有机会使用 Linq,或者您是 .NET-3.5 之前的版本吗?

如果您不能使用 Linq,并且您绝对必须走这条路,请尝试以下操作:

SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE = @ProductCode";
cmd.Prepare();
List<string> results;
foreach (string code in productCodes)
{
    cmd.Parameters.Clear();
    cmd.Parameters.Add("@ProductCodes", DbType.VarChar).Value = code;
    cmd.ExecuteQuery();
    // Add code here to add the returned values to the results list.  It's been
    // a while since I've used ADO.NET, and I don't have time to look it up
    // at the moment...
}

然后,您就得到了结果列表。

For the record, querying the hundred or so values in the array "not separately" could also be inefficient (though not as inefficient as a hundred or so round trips to the SQL Server). However, parameterizing the query helps a bit because you can prepare the same query and execute it several times. A stored procedure could be even better.

Any chance you can use Linq, or are you pre-.NET-3.5?

If you can't use Linq, and you absolutely must go this route, try the following:

SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE = @ProductCode";
cmd.Prepare();
List<string> results;
foreach (string code in productCodes)
{
    cmd.Parameters.Clear();
    cmd.Parameters.Add("@ProductCodes", DbType.VarChar).Value = code;
    cmd.ExecuteQuery();
    // Add code here to add the returned values to the results list.  It's been
    // a while since I've used ADO.NET, and I don't have time to look it up
    // at the moment...
}

And then, you have your list of results.

听,心雨的声音 2024-10-28 19:52:43

您正在寻找表值参数。但是,这些不是'直到 ASP.NET 被广泛采用之后,SQL Server 才可用,因此 ASP.NET 对它们的支持是有限的。

我建议将其视为构建购物车。用户将商品添加到购物车,并且有时您希望显示购物车中的所有商品。在这种情况下,自然的解决方案是购物车本身位于数据库表中。您无需将卡片中的项目下拉为“IN (?)”指令的一部分,而是将其构建为指令的子查询:“WHERE X IN (SELECT X FROM ShoppingCart WHERE UserID= @ UserID AND SessionKey= @SessionKey)”。即使您添加了数百个项目,用户的速度也只会如此之快,并且每次插入的负载分布得相当均匀。

当然,您可能正在构建购物车以外的其他东西,但是您的查询几乎总是属于以下三个类别之一:

  1. 列表中的项目是由用户手动选择的,在这种情况下,您仍然可以拥有每个项目选择结果会产生一个新的数据库记录,该记录又可以在子查询中使用
  2. 它是数据库中已经可用的数据,在这种情况下,您应该仍然能够使用子查询(如果不能,那么可能是时候了在某处添加“类别”列,以便您可以)。
  3. 它是硬编码到您的应用程序中的数据,在这种情况下,您也可以将其编码到您的查询中。

罕见的例外是当查询由另一个机器源触发时,或者您可能还有很多不愿意重新编写的代码。努力使这成为可能。
因此,如果出于某种原因,这种方法不适合您,可以在此处找到有关 sql server 主题的标准文章(包括一些替代方案):
http://www.sommarskog.se/arrays-in-sql.html

这篇文章确实是该主题的标准著作,非常值得您花时间。

You'rel looking for table-valued parameters. However, these weren't available for sql server until well after asp.net was widely adopted, and so the support for them in asp.net is limited.

What I recommend instead is to think of it like building a shopping cart. Users add items to the cart, and at some point you want to display all the items in the cart. In this case, the natural solution is that the shopping cart itself is in a database table rather. Rather than pulling down the items for the card to include as part of an "IN (?)" directive, you build this as a subquery for your directive instead: "WHERE X IN (SELECT X FROM ShoppingCart WHERE UserID= @UserID AND SessionKey= @SessionKey)". Even if you have hundreds of items added, the user is only so going to be so fast and the load per-insert is spread fairly evenly.

Of course, you're probably building something other than a shopping cart, but nevertheless your query will almost always fall into one of three categories:

  1. The items for your list are selected by the user by hand, in which case you can still have each selection result in a new database record that can in turn be used in a subquery
  2. It's data that's already available in your database, in which case you should still be able to use a sub query (and if you can't, it might be time to add a "category" column somewhere so that you can).
  3. It's data that's hard coded into your app, in which case you can also code it into your query

The rare exception is when the query is triggered by another machine source, or you may also have a lot of code that you are reluctant to re-work to make this possible.
So if, for whatever reason, this approach doesn't cut it for you, the standard article on the subject for sql server (including a few alternatives) can be found here:
http://www.sommarskog.se/arrays-in-sql.html

This article really is the standard work on the subject, and is well worth your time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文