【问题标题】:check if values are in datatable检查值是否在数据表中
【发布时间】:2014-10-03 22:01:29
【问题描述】:

我有一个数组或字符串:

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

请问有更快的方法吗?

比较不区分大小写

【问题讨论】:

  • 从我的表中选择计数(*);当执行它。 if (countRec>0) 那么你在表中有记录
  • @realnumber3012 我不是在询问表格中的项目数量。我想检查数组中的值是否存在于表中。该表有 200 多行我可以看到它们

标签: c# sql .net datatable


【解决方案1】:

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

但是,如果您已经有一个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);

【讨论】:

  • 我很困惑:首先你说你应该在数据库中过滤,然后你提供代码在内存中过滤?提供与 Max 完全相同的答案。
  • @Andomar:您已经提供了演示如何在数据库中执行此操作的方法。那我为什么要重复呢?我刚刚尝试回答 OP 的原始问题。 编辑我还没有看到他的回答。然后我可以删除这个。 (尽管 OP 明确要求进行不区分大小写的比较)
  • 我的回答确实看起来过于复杂。数组不是可枚举的。而IList.Contains 似乎没有采用StringComparer 参数...?
  • @Andomar:是Enumerable.Contains(我已经测试过这种方法)。
  • +1 哦,我混淆了enumIEnumerable,谢谢
【解决方案2】:

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

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

【讨论】:

  • 您确定Contains 不区分大小写吗?
  • +1 欢迎来到 SO。 This question 似乎解释了如何使 Contains 不区分大小写
  • 您可以尝试将数据名设为 ToUpper() 或 ToLower(),然后使用 contains dataNames.Contains(row.Field("columnName").ToLower())
  • @Max:不要使用ToUpper/ToLower,那样会在内存中创建很多临时字符串,所以效率很低。它也可能是不正确的。阅读:stackoverflow.com/questions/234591/upper-vs-lower-case 而不是使用StringComparsion/StringComparer
【解决方案3】:

传递值列表非常困难。传递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 或 Tim 的答案。如果表非常大并且无法将其复制到内存中,则可以考虑使用此答案。

【讨论】:

  • 你为什么使用count?请
  • 我需要知道表中存在数组中的哪些值,而不是它们的计数。找我好吗?
  • 我正在尝试您的更新,但我可以输入select distanct col1... 吗?在您的查询中,它不区分大小写,不是吗?
  • 解决方案很难。我将尝试其他答案,+1 感谢您的努力
  • 默认的 SQL 排序规则不区分大小写。如果您希望值多次出现,您可以输入distinct
【解决方案4】:

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

基本上,我有一长串需要返回给客户端的项目 ID,然后客户端会告诉服务器它想要在任何特定时间加载哪些项目 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 子句是为了确保您的搜索只返回您当前正在寻找的唯一项目 - 设计应该考虑到有朝一日会在这里发生并发访问(即使它目前没有),所以建议写一些东西来保护它。

【讨论】:

    猜你喜欢
    • 2012-05-29
    • 1970-01-01
    • 2019-11-13
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多