我有一个数据集,其中包含单个FeeID的学生费用结构,如下所述:
FeeID Amount FeeItem Type
*---------------------------------------------*
10 7500 Admission Fee T
10 900 Annual Fee T
10 150 Application Fee T
10 850 Boy's Uniform T
10 50 Computer Fee R
例如,我有另一个包含以下数据的数据集:
FeeID Amount FeeItem Type
*---------------------------------------------*
9 8500 Admission Fee T
9 950 Annual Fee T
9 150 Application Fee T
9 850 Boy's Uniform T
9 50 Computer Fee R
11 7500 Admission Fee T
11 900 Annual Fee T
11 150 Application Fee T
11 850 Boy's Uniform T
11 50 Computer Fee R
我想检查包含最后三列的集合是否属于另一个数据集,该数据集包含FeeID可能不同的所有费用结构的数据。实际我想要检索具有相同费用结构的匹配FeeID。
在上面的例子中,如果我在第二个中搜索第一个,它将返回 True ,匹配的FeeID将 11 。
答案 0 :(得分:2)
您可以使用this技巧
Dataset ds1
DataSet ds2
DataSet dest;
dest.Merge(ds1);
dest.AcceptChanges();
dest.Merge(ds2);
diff = destination.GetChanges()
并检查diff是否为空
答案 1 :(得分:1)
修改:我对以下代码做了一些改进。以下DataTable.IndexOf(otherTable)
扩展方法检查表是否是另一个表的子集。
您可以在比较中传递要忽略的列名。列的顺序无关紧要,但DataRows
的顺序(子集必须具有相同的行顺序)。
当没有找到DataRows
的相等子集时,它返回-1,或者在相同子集开始的主表(扩展名为this
)中的第一个索引。
public static class DataTableExtensions
{
public static int IndexOf(this DataTable tblMain, DataTable tblSub, params String[] ignoreColumns)
{
if (tblMain == null)
throw new ArgumentNullException("tblMain");
if (tblSub.Rows.Count == 0)
throw new ArgumentException("tblSub must not be empty", "tblSub");
if (tblSub.Rows.Count > tblMain.Rows.Count)
return -1;
IEnumerable<String> relevantColumnNames = tblSub.Columns.Cast<DataColumn>()
.Select(c => c.ColumnName)
.Except(ignoreColumns)
.ToArray();
foreach (String colName in relevantColumnNames)
if (!tblMain.Columns.Contains(colName))
return -1;
for (int mainRowIndex = 0; tblMain.Rows.Count - mainRowIndex >= tblSub.Rows.Count; mainRowIndex++)
{
// check if current window is equal to tblSub
bool allRowsAreEqual = true;
for (int windowIndex = mainRowIndex; windowIndex < tblSub.Rows.Count + mainRowIndex; windowIndex++)
{
DataRow currentMain = tblMain.Rows[windowIndex];
DataRow currentSub = tblSub.Rows[windowIndex - mainRowIndex];
bool allFieldsAreEqual = relevantColumnNames.All(colName =>
Object.Equals(currentMain[colName], currentSub[colName]));
if (!allFieldsAreEqual)
{
allRowsAreEqual = false;
break; // continue with next window in main-table
}
}
if (allRowsAreEqual)
return mainRowIndex;
}
// no equal window found in main-table
return -1;
}
}
您的样本数据:
var TblSub = new DataTable();
var TblMain = new DataTable();
TblSub.Columns.Add("FeeID", typeof(int));
TblSub.Columns.Add("Amount", typeof(int));
TblSub.Columns.Add("FeeItem", typeof(string));
TblSub.Columns.Add("Type", typeof(char));
TblMain.Columns.Add("FeeID", typeof(int));
TblMain.Columns.Add("Amount", typeof(int));
TblMain.Columns.Add("FeeItem", typeof(string));
TblMain.Columns.Add("Type", typeof(char));
TblSub.Rows.Add(10, 7500, "Admission Free", 'T');
TblSub.Rows.Add(10, 900, "Annual Fee", 'T');
TblSub.Rows.Add(10, 150, "Application Free", 'T');
TblSub.Rows.Add(10, 850, "Boy's Uniform", 'T');
TblSub.Rows.Add(10, 50, "Computer Free", 'R');
TblMain.Rows.Add(9, 8500, "Admission Free", 'T');
TblMain.Rows.Add(9, 950, "Annual Fee", 'T');
TblMain.Rows.Add(9, 150, "Application Free", 'T');
TblMain.Rows.Add(9, 850, "Boy's Uniform", 'T');
TblMain.Rows.Add(9, 50, "Computer Free", 'R');
TblMain.Rows.Add(10, 7500, "Admission Free", 'T');
TblMain.Rows.Add(11, 900, "Annual Fee", 'T');
TblMain.Rows.Add(11, 150, "Application Free", 'T');
TblMain.Rows.Add(11, 850, "Boy's Uniform", 'T');
TblMain.Rows.Add(11, 50, "Computer Free", 'R');
您可以这样使用它:
int firstIndex = TblMain.IndexOf(TblSub, "FeeID");
if (firstIndex == -1)
Console.Write("Second table does not contain first table");
else
Console.Write("Second table does contain first table at row-index " + firstIndex);
输出是:
第二个表确实包含第一行 - 第5行
旧方法:
您可以使用以下方法检查两个DataTable是否相等。
您需要为Enumerable.SequenceEqual
添加using System.Linq
。如果你不能使用Linq,请使用循环。
static bool TablesEqual(DataTable table1, DataTable table2, params int[] skipColumns)
{
if (table1.Rows.Count != table2.Rows.Count)
return false;
for (int i = 0; i < table1.Rows.Count; i++)
{
var array1 = table1.Rows[i].ItemArray
.Where((obj, index) => !skipColumns.Contains(index));
var array2 = table2.Rows[i].ItemArray
.Where((obj, index) => !skipColumns.Contains(index)); ;
if (!array1.SequenceEqual(array2))
{
return false;
}
}
return true;
}
您只需要传递您想要忽略的列的索引,例如:
bool allEqual = TablesEqual(t1, t2); // all equal
bool equalIgnore0 = TablesEqual(t1, t2, 0); // ignore first column
bool equalIgnore0and2 = TablesEqual(t1, t2, 0, 2); // ignore first and third column
答案 2 :(得分:0)
最后,我能够解决这个问题。以下是我的功能。我正在使用 Tim Schmelter 提供的 TablesEqual 功能。该函数将返回有效的 FeeID ,如果未找到匹配项,则为正整数,否则为-1。
private int MatchFeeID(DataTable Dt)
{
DataTable mainDt = bl.GetDataSet("Select * From FeeMaster"); //assume this is a function that will return all the fee structures from database.
var fids = (from row in mainDt.AsEnumerable().Distinct()
group row by row.Field<string>("fid") into rowGroup
select new
{
fid = rowGroup.Key
});
foreach (var fid in fids)
{
string id = fid.fid;
DataTable t1 = new DataTable();
DataTable t2 = new DataTable();
DataRow[] dr1 = mainDt.Select(String.Format("fid = '{0}'", id));
t1 = dr1.CopyToDataTable();
t2 = Dt;
bool res = TablesEqual(t1, t2, 0, 1);
if (res) return Convert.ToInt32(id);
}
return -1;
}