我正在开发的项目有很多IN查询,如:
SELECT something, anotherthing
FROM atable
WHERE something IN (value1, value2, value3)
这是在IN部分中具有3个参数的查询的示例,但是可以使用1或2或5或10或...参数执行相同的查询。 问题是每个查询在数据库中都有另一个执行计划,使其变慢。
我想讨论这样的问题:
SELECT something, anotherthing
FROM atable
WHERE something IN (@value1, @value2, @value3)
或者这个:
SELECT something, anotherthing
FROM atable
WHERE something IN (@values)
我已经用一些辅助函数完成了第一个查询,但是每个参数的数量仍然有不同的执行计划。这可以用第二个解决。
将数组作为数据库参数传递的最佳方法是什么?我正在使用Oracle和SQL Server,欢迎使用它们的解决方案。
答案 0 :(得分:4)
对于SQL-Server,有两种常见的方法。第三个选项要避免是传入varchar
并将其连接到带有IN
的动态SQL语句中 - 这是一个清晰的注入攻击面。
合理的选择:
传入varchar
并使用UDF将数据拆分为分隔符(like in this question),可能是逗号,管道,制表符等。加入结果:
SELECT something, anotherthing
FROM atable a
INNER JOIN dbo.SplitUDF(@values) udf
ON udf.Value = a.something
答案 1 :(得分:1)
看一下这些文章
这是使用XML类型创建列表
的示例--Split
DECLARE @textXML XML
DECLARE @data NVARCHAR(MAX),
@delimiter NVARCHAR(5)
SELECT @data = 'A,B,C',
@delimiter = ','
SELECT @textXML = CAST('<d>' + REPLACE(@data, @delimiter, '</d><d>') + '</d>' AS XML)
SELECT T.split.value('.', 'nvarchar(max)') AS data
FROM @textXML.nodes('/d') T(split)
答案 2 :(得分:0)
这段代码可以解决问题。您可以创建自己的BuildQuery(???)函数。
public void RemoveDependencies(int versionID, int[] deps)
{
if (versionID <= 0)
throw new ArgumentException();
if (deps == null)
throw new ArgumentNullException();
if (deps.Length <= 0)
throw new ArgumentException();
SqlCommand cmd = new SqlCommand();
string query = "DELETE FROM Dependencies WHERE version_id = @VersionId AND dep_version_id IN (";
int n = deps.Length;
string key;
for (int i = 0; i < n; i++)
{
if (deps[i] <= 0)
throw new ArgumentException();
key = String.Format("@dep{0}", i);
query += key;
cmd.Parameters.AddWithValue(key, deps[i]);
if (i < n - 1)
{
query += ", ";
}
}
query += ")";
cmd.Parameters.AddWithValue("@VersionId", versionID);
cmd.CommandText = query;
using (SqlConnection con = GetSqlConnection())
{
con.Open();
cmd.Connection = con;
if (cmd.ExecuteNonQuery() <= 0)
{
throw new ArgumentException("No rows affected! Illegal id.");
}
}
}