检查值是否在数据表中

时间:2014-08-11 06:37:01

标签: c# sql .net datatable

我有一个数组或字符串:

private static string[] dataNames = new string[] {"value1", "value2".... };

我的SQL数据库中有一个varchar类型的表。我想检查该列中是否存在字符串数组中的哪些值。

我试过了:

public static void testProducts() {
            string query = "select * from my table"
            var dataTable = from row in dt.AsEnumerable()
                            where String.Equals(row.Field<string>("columnName"), dataNames[0], StringComparison.OrdinalIgnoreCase)
                            select new { 
                                Name = row.Field<string> ("columnName")
                            };
            foreach(var oneName in dataTable){
                Console.WriteLine(oneName.Name);
            }
        }

该代码不是实际代码,我只是想向您展示重要部分

您看到的代码根据dataNames[index]

进行检查

它工作正常,但我必须运行该代码56次,因为该数组有56个元素,每次我更改index

请问有更快的方法吗?

比较不区分大小写

4 个答案:

答案 0 :(得分:2)

传递值列表非常困难。传递a table-valued parameter需要在服务器上创建T-SQL数据类型。您可以传递包含参数的XML文档,并使用SQL Server convoluted XML syntax对其进行解码。

以下是一个相对简单的替代方案,适用于多达一千个值。目标是构建in查询:

select col1 from YourTable where col1 in ('val1', 'val2', ...)

在C#中,您应该使用参数:

select col1 from YourTable where col1 in (@par1, @par2, ...)

您可以传递的内容如下:

var com = yourConnection.CreateCommand();
com.CommandText = @"select col1 from YourTable where col1 in (";
for (var i=0; i< dataNames.Length; i++)
{
    var parName = string.Format("par{0}", i+1);
    com.Parameters.AddWithValue(parName, dataNames[i]);
    com.CommandText += parName;
    if (i+1 != dataNames.Length)
        com.CommandText += ", ";
}
com.CommandText += ");";
var existingValues = new List<string>();
using (var reader = com.ExecuteReader())
{
    while (read.Read())
        existingValues.Add(read["col1"]);
}

考虑到这个解决方案的复杂性,我选择Max&#39;或蒂姆的回答。如果表格非常大并且您无法将其复制到内存中,您可以考虑这个答案。

答案 1 :(得分:2)

尝试使用contains应返回所需的所有值

var data = from row in dt.AsEnumerable()
                   where dataNames.Contains(row.Field<string>("columnName"))
                   select new
                   {
                       Name = row.Field<string>("columnName")
                   };

答案 2 :(得分:2)

首先,您不应该在内存中但在数据库中过滤记录。

但是,如果您已经拥有DataTable并且需要找到其中某个字段位于string[]中的行,则可以使用Linq-To-DataTable

例如Enumerable.Contains

var matchingRows = dt.AsEnumerable()
    .Where(row => dataNames.Contains(row.Field<string>("columnName"), StringComparer.OrdinalIgnoreCase));

foreach(DataRow row in matchingRows)
    Console.WriteLine(row.Field<string>("columnName"));

使用Enumerable.Join

,这是一种更有效(但不太可读)的方法
var matchingRows = dt.AsEnumerable().Join(dataNames,
    row => row.Field<string>("columnName"),
    name => name,
    (row, name) => row,
    StringComparer.OrdinalIgnoreCase);

答案 3 :(得分:0)

对不起,我这里没有很多相关的代码,但很久以前我做了类似的事情,所以我会尝试解释一下。

基本上我有一个很长的项目ID列表,我需要返回到客户端,然后告诉服务器它在任何特定时间加载了哪些。原始查询将值作为逗号分隔的字符串集传递(它们实际上是GUID)。问题是,一旦条目数达到100,用户就会有明显的滞后,一旦达到1000个可能的条目,查询花了一分半钟,当我们达到10,000时,我们只能说你可以煮沸水壶,在你回来之前喝茶/咖啡。

答案是坚持将值直接检查到临时表中,其中表的一行表示要检查的值。临时表是针对执行搜索的用户键入的,因此这意味着其他用户搜索不会相互损坏,并且当用户注销时,我们就知道搜索表中的哪些值可以被删除。

取决于此数据的来源取决于您加载参考表的最佳方式。但是一旦它存在,那么你的新查询将类似于: -

SELECT Count(t.*), rt.dataName
FROM table t
RIGHT JOIN referenceTable rt ON tr.dataName = t.columnName
WHERE rt.userRef = @UserIdValue
GROUP BY tr.dataName

此处的RIGHT JOIN应为您的每个参考表值提供一个值,如果该值未出现在您的表中,则包括0。如果您不关心哪一个不出现,那么将其更改为INNER JOIN将消除零。

WHERE子句是为了确保您的搜索仅返回您当前正在查找的唯一项目 - 设计应该考虑有一天会发生并发访问(即使它现在还没有) ,所以写一些东西来保护它是可取的。