如何仅将唯一列与数据连接

发布于 2025-01-04 12:10:35 字数 1563 浏览 1 评论 0原文

我在下面使用这个:

    public static DataTable DataTableJoiner(DataTable dt1, DataTable dt2)
    {
        using (DataTable targetTable = dt1.Clone())
        {
            var dt2Query = dt2.Columns.OfType<DataColumn>().Select(dc =>
                new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, 
                    dc.ColumnMapping));
            var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
                                 where targetTable.Columns
                                       .Contains(dc.ColumnName) == false
                                 select dc;
            targetTable.Columns.AddRange(dt2FilterQuery.ToArray());
            var rowData = from row1 in dt1.AsEnumerable()
                          join row2 in dt2.AsEnumerable()
                          on row1.Field<int>("Code") equals 
                             row2.Field<int>("Code")
                          select row1.ItemArray
                              .Concat(row2.ItemArray
                              .Where(r2 => 
                                  row1.ItemArray.Contains(r2) == false)).ToArray();
            foreach (object[] values in rowData) targetTable.Rows.Add(values);
            return targetTable;
        }
    }

这行有一个问题:

select row1.ItemArray.Concat(row2.ItemArray.Where(r2 => 
     row1.ItemArray.Contains(r2) == false)).ToArray();

它似乎在说,如果这个值(而不是列)已经存在,则不要包含我。

我使用此方法根据两个表共享的列将两个表连接在一起,但我只希望包含两个表数据的唯一列作为最终结果。

有什么想法吗?

I am using this below:

    public static DataTable DataTableJoiner(DataTable dt1, DataTable dt2)
    {
        using (DataTable targetTable = dt1.Clone())
        {
            var dt2Query = dt2.Columns.OfType<DataColumn>().Select(dc =>
                new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, 
                    dc.ColumnMapping));
            var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
                                 where targetTable.Columns
                                       .Contains(dc.ColumnName) == false
                                 select dc;
            targetTable.Columns.AddRange(dt2FilterQuery.ToArray());
            var rowData = from row1 in dt1.AsEnumerable()
                          join row2 in dt2.AsEnumerable()
                          on row1.Field<int>("Code") equals 
                             row2.Field<int>("Code")
                          select row1.ItemArray
                              .Concat(row2.ItemArray
                              .Where(r2 => 
                                  row1.ItemArray.Contains(r2) == false)).ToArray();
            foreach (object[] values in rowData) targetTable.Rows.Add(values);
            return targetTable;
        }
    }

There is a problem with this line:

select row1.ItemArray.Concat(row2.ItemArray.Where(r2 => 
     row1.ItemArray.Contains(r2) == false)).ToArray();

It seems to be saying don't include me if this value (rather than column) already exists.

I am using this method to join two tables together based on a column that both tables share, but I only want the unique columns with data of both tables as a final result.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

So尛奶瓶 2025-01-11 12:10:35

我不确定我是否 100% 理解您的要求,但这:

row2.ItemArray.Where(r2 => row1.ItemArray.Contains(r2) == false)

将过滤掉那些恰好出现在表 1 任何列中的项目,而不仅仅是您要加入的列。

所以我想做的是根据索引过滤项目,使用 Where 扩展方法的重载:

// Get the index of the column we are joining on:
int joinColumnIndex = dt2.Columns.IndexOf("Code");

// Now we can filter out the proper item in the rowData query:
row2.ItemArray.Where((r2,idx) => idx != joinColumnIndex)

...

不,等等。这里:

var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
                     where targetTable.Columns
                           .Contains(dc.ColumnName) == false
                     select dc;

你是过滤掉表 2 中名称也出现在表 1 中的所有列。所以您可能想要的是这样的:

public static DataTable DataTableJoiner(DataTable dt1, DataTable dt2)
{
    DataTable targetTable = dt1.Clone();

    var dt2Query = dt2.Columns.OfType<DataColumn>().Select(dc =>
        new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, 
            dc.ColumnMapping));

    var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
                         where !targetTable.Columns.Contains(dc.ColumnName)
                         select dc;

    var columnsToAdd = dt2FilterQuery.ToArray();
    var columnsIndices = columnsToAdd.Select(dc => dt2.Columns.IndexOf(dc.ColumnName));

    targetTable.Columns.AddRange(columnsToAdd);

    var rowData = from row1 in dt1.AsEnumerable()
                      join row2 in dt2.AsEnumerable()
                      on row1.Field<int>("Code") equals 
                         row2.Field<int>("Code")
                      select row1.ItemArray
                          .Concat(row2.ItemArray
                          .Where((r2,idx) => 
                              columnsIndices.Contains(idx))).ToArray();

    foreach (object[] values in rowData) targetTable.Rows.Add(values);
    return targetTable;
}

顺便说一句。我不太明白为什么您将返回的 DataTable 包装在 using 语句中。恕我直言,立即处理您返回给调用者的对象是毫无意义的......

I am not sure if I understand your requirement 100%, but this:

row2.ItemArray.Where(r2 => row1.ItemArray.Contains(r2) == false)

will filter out those items that happen to appear in any column of table 1, not just the column you are joining on.

So what I would try to do is filter the item based on the index, using an overload of the Where extension method:

// Get the index of the column we are joining on:
int joinColumnIndex = dt2.Columns.IndexOf("Code");

// Now we can filter out the proper item in the rowData query:
row2.ItemArray.Where((r2,idx) => idx != joinColumnIndex)

...

No, wait. Here:

var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
                     where targetTable.Columns
                           .Contains(dc.ColumnName) == false
                     select dc;

You are filtering out all columns of table 2 whose name also appear in table 1. So what you probably want is this:

public static DataTable DataTableJoiner(DataTable dt1, DataTable dt2)
{
    DataTable targetTable = dt1.Clone();

    var dt2Query = dt2.Columns.OfType<DataColumn>().Select(dc =>
        new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, 
            dc.ColumnMapping));

    var dt2FilterQuery = from dc in dt2Query.AsEnumerable()
                         where !targetTable.Columns.Contains(dc.ColumnName)
                         select dc;

    var columnsToAdd = dt2FilterQuery.ToArray();
    var columnsIndices = columnsToAdd.Select(dc => dt2.Columns.IndexOf(dc.ColumnName));

    targetTable.Columns.AddRange(columnsToAdd);

    var rowData = from row1 in dt1.AsEnumerable()
                      join row2 in dt2.AsEnumerable()
                      on row1.Field<int>("Code") equals 
                         row2.Field<int>("Code")
                      select row1.ItemArray
                          .Concat(row2.ItemArray
                          .Where((r2,idx) => 
                              columnsIndices.Contains(idx))).ToArray();

    foreach (object[] values in rowData) targetTable.Rows.Add(values);
    return targetTable;
}

Btw. I don't quite understand why you are wrapping the DataTable you return in a using statement. Imho it is kind of pointless to dispose the very object you return to your caller right away...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文