我在管道分隔的文本文件和数据库表中包含相同模式的数据,包括主键列。
我必须检查文件中的每一行是否存在于表中,如果没有为该行生成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();
编辑:对不起,我错过了询问实际问题;这该怎么做?
非常感谢您的帮助。
编辑:该表有100多万行,而文件有50K行。这是一次性的事情,而不是永久性的项目。
答案 0 :(得分:2)
尝试使用.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);
}
答案 1 :(得分: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();
答案 2 :(得分: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加载到HashSet
,然后只检查HashSet
以查看它是否存在 - 需要更长的时间开始,但每个记录会更快。
这三种技术中的任何一种都可以使用 - 这取决于数据库表的大小,以及文件的大小。如果它们都相对较小(可能是10,000条记录左右),那么其中任何一条都可以正常工作。
修改强>
总是有选项D:将文件中的所有记录插入数据库中的临时表(可能是真实表或SQL临时表,并不重要),然后使用SQL将两个表连接在一起并检索差异(使用not exists
或in
或您想要的任何技术),然后以这种方式插入缺失的记录。