C# 如何检查一个数据集是否属于另一个数据集

C# 如何检查一个数据集是否属于另一个数据集,c#,.net,sql,C#,.net,Sql,我有一个数据集,其中包含单个FeeID的学费结构,如下所述: FeeID Amount FeeItem Type *---------------------------------------------* 10 7500 Admission Fee T 10 900 Annual Fee T 10

我有一个数据集,其中包含单个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

,您可以使用技巧


并检查diff是否为空

编辑:我对下面的代码做了一些改进。扩展方法检查一个表是否是另一个表的子集

您可以传递要在比较中忽略的列名。列的顺序无关紧要,但数据行的顺序无关紧要(子集必须具有相同的行顺序)

当未找到
DataRows
的等分集或等分集开始的主表(
this
)中的第一个索引时,它返回-1

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;
    }
}
您可以这样使用它:

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行索引中包含第一个表


旧方法

您可以使用以下方法检查两个数据表是否相等

您需要使用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;
}

我终于能够解决这个问题了。以下是我的功能。我正在使用Tim Schmelter提供的函数tableequal。如果没有找到匹配项,该函数将返回一个有效的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;
}
private int MatchFeeID(数据表Dt)
{
DataTable mainDt=bl.GetDataSet(“Select*From FeeMaster”);//假设这是一个函数,将从数据库返回所有费用结构。
var fids=(来自mainDt.AsEnumerable().Distinct()中的行)
按行分组。字段(“fid”)分为行组
选择新的
{
fid=行组。键
});
foreach(fids中的var fid)
{
字符串id=fid.fid;
DataTable t1=新的DataTable();
DataTable t2=新的DataTable();
DataRow[]dr1=mainDt.Select(String.Format(“fid=”{0}',id));
t1=dr1.CopyToDataTable();
t2=Dt;
bool res=表相等(t1,t2,0,1);
if(res)返回Convert.ToInt32(id);
}
返回-1;
}

DataSet不是DataTable的同义词。是否要检查两个不同DataTable中所有行中所有字段的所有值是否相同?顺序重要吗?是否要将表的子集(例如按FeeID分组(因为它们始终为10))与另一个表进行比较,还是所有行都必须相同?什么意思是“我想检索具有相同费用结构的匹配FeeID?”?这意味着给我FeeID具有与给定费用ID的费用结构相同的费用结构(在本例中为10)。嗨,Tim,请查看我最后的评论。这不是我想要的确切解决方案。我没有检查整行,而是检查除第一列(即FeeID)之外的所有其他列。秩序也很重要。@Mahbub:编辑了我的答案。因为我比较每一行,所以会考虑顺序。记住,第一个表中的行数总是小于第二个表中的行数。因此,我认为第一个if条件在这里不适用。嗨,蒂姆,我已经通过给出详细的例子详细阐述了我的问题。请再次检查。@Mahbub:编辑了我的答案,以防其他人正在查找
DataTable.IndexOf(otherTable)
方法。请注意,您不需要初始化DataTables(构造函数可能很昂贵)。第一个表由
dr1.CopyToDataTable
初始化,第二个表由
DT
初始化。除此之外,我的方法使用
SequenceEquals
itemrarray
查找每行的值。这仅在列的顺序相同时才有效。是否需要一种方法来比较独立于列顺序的字段?
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
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;
}