1

我在管道分隔的文本文件和数据库表(包括主键列)中有具有相同架构的数据。

我必须检查文件中的每一行是否存在于表中,如果没有为该行生成 INSERT 语句。

该表有 30 列,但在这里我为这个示例进行了简化:

ID       Name    Address1    Address2    City    State    Zip

ID是运行标识列;因此,如果在表中找到文件中的特定 ID 值,则不应insert为此生成任何语句。

这是我的尝试,感觉不正确:

 foreach (var item in RecipientsInFile)
        {
            if (!RecipientsInDB.Any(u => u.ID == item.ID ))
            {
               Console.WriteLine(GetInsertSql(item));
            }
        }
        Console.ReadLine();

编辑:对不起,我错过了提出实际问题;这该怎么做?非常感谢您提供的所有帮助。

编辑:表有一百万多行,而文件有 50K 行。这是一次性的事情,而不是永久的项目。

4

3 回答 3

2

尝试使用比较 ID 列表.Except()

List<int> dbIDs = Recipients.Select(x=>x.ID).ToList();
List<int> fileIDs = RecipientsFile.Select(x=>x.ID).ToList();
List<int> toBeInserted = fileIDs.Except(dbIDs).ToList();

toBeInserted.ForEach(x=>GetInsertSqlStatementForID(x));

对于评论中我们中间的迂腐和巨魔,请记住上面的代码(就像您在互联网上找到的任何源代码一样)不应该被复制/粘贴到您的生产代码中。试试这个重构:

foreach (var item in RecipientsFile.Select(x=>x.ID)
                                   .Except(DatabaseRecipients.Select(x=>x.ID)))
{
   GetInsertSqlStatementForID(item);
}
于 2013-03-20T15:19:53.987 回答
2

我将在HashSet中添加所有 RecipientsInDB Id ,然后测试该集合是否包含项目 Id。

 var recipientsInDBIds = new Hashset(RecipientsInDB.Select(u => u.ID));
 foreach (var item in RecipientsInFile)
    {
        if (!recipientsInDBIds.Contains(item.ID ))
        {
           Console.WriteLine(GetInsertSql(item));
        }
    }
    Console.ReadLine();
于 2013-03-20T15:21:36.597 回答
0

实现这一点的方法很多。你的方法是一种。

另一种方法是始终生成 SQL,但以下列方式生成它:

if not exists (select 1 from Recipients where ID == 1234)
    insert Recipients (...) values (...)
if not exists (select 1 from Recipients where ID == 1235)
    insert Recipients (...) values (...)

另一种方法是预先将数据库的全部内容检索到内存中,将数据库 ID 加载到 aHashSet中,然后只检查HashSet它是否存在 - 开始需要更长的时间,但每条记录会更快。

这三种技术中的任何一种都可以工作——这完全取决于你的数据库表有多大,以及你的文件有多大。如果它们都相对较小(可能有 10,000 条左右),那么它们中的任何一个都应该可以正常工作。

编辑

并且总是有选项 D:将文件中的所有记录插入数据库中的临时表(可以是真实表或 SQL 临时表,并不重要),然后使用 SQL 将两个表连接在一起并检索差异(使用not existsin您想要的任何技术),并以这种方式插入丢失的记录。

于 2013-03-20T15:20:53.687 回答