我有两个非常相似但有其他列名的数据表。第一个Datatable有4列,大约有7000条记录。第二个也有4列和约37000条记录。现在我想显示第三个数据网格视图中第一个数据表中缺少的记录。我该怎么做?我知道互联网上有很多代码,但没有任何效果。
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Linq;
using System.Data.OleDb;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
namespace Compare
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
DataTable ds;
DataTable dt;
public void btn_Click(object sender, EventArgs e)
{
SqlDataAdapter adapter = new SqlDataAdapter("select a.FALLZAHL, m.CODE, m.ANZ, m.STDAT From test m with (nolock) inner join test2 a with (nolock) on a.id = m.aid where m.STDAT >= '2016-01-01' and m.STALT = '6363' order by a.FALLZAHL", "Server = ada; Database = sd;Trusted_Connection = True");
ds = new DataTable(" ");
adapter.Fill(ds);
dataGridView1.DataSource = ds;
}
private void Excelsheet_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();
}
private void choose_Click(object sender, EventArgs e)
{
OpenFileDialog OpenFileDialog = new OpenFileDialog();
}
private string Excel03ConString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties='Excel 8.0;HDR={1}'";
private string Excel07ConString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 8.0;HDR={0}'";
public void openFileDialog1_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
{
string filePath = openFileDialog1.FileName;
string extension = Path.GetExtension(filePath);
string header = radioButton1.Checked ? "YES" : "NO";
string conStr, sheetName, cells;
conStr = string.Empty;
switch (extension)
{
case ".xls": //Excel 97-03
conStr = string.Format(Excel03ConString, filePath, header);
break;
case ".xlsx": //Excel 07
conStr = string.Format(Excel07ConString, filePath, header);
break;
}
using (OleDbConnection con = new OleDbConnection(conStr))
{
using (OleDbCommand cmd = new OleDbCommand())
{
cmd.Connection = con;
con.Open();
System.Data.DataTable dtExcelSchema = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
sheetName = dtExcelSchema.Rows[0]["TABLE_NAME"].ToString();
con.Close();
}
}
using (OleDbConnection con = new OleDbConnection(conStr))
{
using (OleDbCommand cmd = new OleDbCommand())
{
using (OleDbDataAdapter oda = new OleDbDataAdapter())
{
dt = new DataTable();
cmd.CommandText = "SELECT * From [" + sheetName + "]";
cmd.Connection = con;
con.Open();
oda.SelectCommand = cmd;
oda.Fill(dt);
con.Close();
dataGridView2.DataSource = dt;
}
}
}
}
private void dataGridView3_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
/* dataGridView3.DataSource = from table1 in ds.AsEnumerable()
join table2 in dt.AsEnumerable() on table1.Field<int>("ColumnA") equals table2.Field<int>("ColumnA")
where table1.Field<int>("ColumnB") == table2.Field<int>("ColumnB") || table1.Field<string>("ColumnC") == table2.Field<string>("ColumnC") || table1.Field<object>("ColumnD") == table2.Field<object>("ColumnD")
select table1;
dataGridView3.DataSource = from table1 in ds.AsEnumerable()
where !dataGridView3.Contains(table1)
select table1;
*/
}
public void CompareData()
{
}
private void button1_Click(object sender, EventArgs e)
{
var dsRowCount = ds.AsEnumerable().Count();
var dtRowCount = dt.AsEnumerable().Count();
if (dsRowCount > dtRowCount)
{
//Set main table to be dt as this has the least number of rows.
dataGridView3.DataSource = NoMatches(dt, ds);
}
else
{
//Set main table to ds as this has the least number of rows OR tables have the same number of rows.
dataGridView3.DataSource = NoMatches(ds, dt);
}
}
private IEnumerable<DataRow> NoMatches(DataTable MainTable, DataTable SecondaryTable)
{
var matched = from table1 in MainTable.AsEnumerable()
join table2 in SecondaryTable.AsEnumerable()
on table1.Field<string>("ISH_FALLZAHL") equals table2.Field<string>("FAL")
where (table1.Field<string>("ML_CODE").Equals(table2.Field<string>("LST")))
|| Convert.ToInt32(table1.Field<Int16>("ML_ANZ")) == Convert.ToInt32(table2.Field<double>("ST"))
select table1;
return MainTable.AsEnumerable().Except(matched);
}
// dataGridView3.DataSource = CompareTables();
}
/* public bool DatatablesAreSame()
{
if (ds.Rows.Count == dt.Rows.Count)
return true;
foreach (DataColumn dc in ds.Columns)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
if (ds.Rows[i][dc.ColumnName = "ISH_FALLZAHL"] != dt.Rows[i][dc.ColumnName = "FAL"])
{
}
}
}
return true;
}
*/
/*
private void CompareTables()
{
try
{
var dt1Records = ds.AsEnumerable().Select(e1 => new { Id = e1["ISH_FALLZAHL"].ToString(), Name = e1["FAL"].ToString() });
var dt2Records = dt.AsEnumerable().Select(e2 => new { Id = e2["ISH_FALLZAHL"].ToString(), Name = e2["FAL"].ToString() });
var extraRecords = dt1Records.Except(dt2Records);
dataGridView3.DataSource = extraRecords;
}
catch (Exception ex)
{ }
}
*/
}
答案 0 :(得分:1)
要比较数据集中的2个数据表,您需要实际引用这些表。查看代码时,您似乎正在尝试将已从电子表格填充的数据表连接到整个数据集,这将无法正常工作。
尝试这样的事情:
var matched = from table1 in ds.Tables["Your Table"].AsEnumerable()
join table2 in dt2.AsEnumerable()
on table1.Field<string>("ColumnA") equals table2.Field<string>("ColumnC")
where (table1.Field<string>("ColumnB").Equals(table2.Field<string>("ColumnA")))
|| (table1.Field<int>("ColumnC") == table2.Field<int>("ColumnD"))
select table1;
<强> 更新 强>
如果'ds'实际上是一个数据表,那么请进行以下更改:
var matched = from table1 in ds.AsEnumerable()
更新2
根据评论中的图片,映射应该是:
table1.ColumnA = table2.ColumnC - 将其设置为字符串
table1.ColumnB = table2.ColumnA - 将其设置为字符串
table1.ColumnC = table2.ColumnD - 将其设置为int
看起来你应该改变你投射的类型。我已经更新了查询。
更新3
按照我之前的评论尝试从两个数据表中删除案例编号并进行比较。这将告诉您连接是否应返回任何值。为此,您可以使用以下查询:
var dsCaseNumbers = ds.AsEnumerable().Select(x => x.Field<string>("ColumnA").ToList();
这将返回ds中仅包含案例编号的列表。使用dt:
的相同查询创建另一个列表var dtCaseNumbers = dt.AsEnumerable().Select(x => x.Field<string>("ColumnC").ToList();
然后通过执行以下方式比较2:
var HasMatches = dsCaseNumbers.Any(y => dtCaseNumbers.Contains(y));
如果dsCaseNumbers和dtCaseNumbers之间存在匹配,那么'HasMatches'将为true,否则则为false。
更新4
要仅显示差异,您可以使用以下内容:
var NoMatches = ds.AsEnumerable().Except(matched);
然后,您可以使用“NoMatches”作为另一个数据网格的数据源。如果'NoMatches'由具有最多行的表确定并且不总是'ds',则将查询包装在一个方法中,该方法采用'main table'参数和'secondary table'参数,如下所示:
private IEnumerable<DataRow> NoMatches (DataTable MainTable, DataTable SecondaryTable)
{
var matched = from table1 in MainTable.AsEnumerable()
join table2 in SecondaryTable.AsEnumerable()
on table1.Field<string>("ColumnA") equals table2.Field<string>("ColumnC")
where (table1.Field<string>("ColumnB").Equals(table2.Field<string>("ColumnA")))
|| (table1.Field<int>("ColumnC") == table2.Field<int>("ColumnD"))
select table1;
return MainTable.AsEnumerable().Except(matched);
}
然后,首先只计算每个表中的行,以确定哪个表应该是主表,并调用上面概述的方法。
更新5
因此,要使用上述方法并在新的数据网格中显示不匹配,您可以执行以下操作:
//First determine which table should be considered 'Main'. This will be the one with the LEAST number of rows.
var dsRowCount = ds.AsEnumerable().Count();
var dtRowCount = dt.AsEnumerable().Count();
if (dsRowCOunt > dtRowCount)
{
//Set main table to be dt as this has the least number of rows.
datagridView.Datasource = NoMatches(dt, ds);
}
else
{
//Set main table to ds as this has the least number of rows OR tables have the same number of rows.
datagridView.Datasource = NoMatches(ds, dt);
}
更新6
编辑私有IEnumerable NoMatches以返回DataTable,如下所示:
private DataTable NoMatches (DataTable MainTable, DataTable SecondaryTable)
{
var matched = from table1 in MainTable.AsEnumerable()
join table2 in SecondaryTable.AsEnumerable()
on table1.Field<string>("ColumnA") equals table2.Field<string>("ColumnC")
where (table1.Field<string>("ColumnB").Equals(table2.Field<string>("ColumnA")))
|| (table1.Field<int>("ColumnC") == table2.Field<int>("ColumnD"))
select table1;
return MainTable.AsEnumerable().Except(matched).CopyToDataTable();
}
注意2个变化;方法签名和返回使用'CopyToDataTable()'