簡體   English   中英

如何在C#中使用公共列對2個或更多數據表進行完全外部聯接

[英]How to do a Full Outer Join of 2 or more Datatables in C# with a common column

我需要將C#上的數據表合並/聯接到一個公共列。

我知道有人問過許多關於同一主題的例子和問題。 我還沒有找到任何答案。

下面是我正在使用的代碼。

該代碼僅基於datatable上的數據允許一個公共列。 我需要一個公共列,但它需要考慮可以在另一個數據表中使用任何其他“ Account#”並將其添加到公共列中。

此外,該代碼僅允許合並2個數據表。 我需要合並31個數據表,每個月的每一天要合並1個數據表。

我每個月的每一天都有一個數據表,分別為dt_docDAY01,dt_docDAY02,dt_docDAY03等。

每個數據表都包含一個帳號“ Account#”和一個余額,該余額存儲在引用“ DAY01”,“ DAY02”等天的列中。

您能告訴我如何更改代碼,以便我將包括所有表中的所有帳戶。

另外,我將如何在此代碼中合並所有數據表,因此我不必運行相同的代碼31次。

'string id =“ Account#”;

                var tableJoinedDAY02 = dt_docDAY01_GROUPED.Clone(); // create columns from table1

                // add columns from table2 except id
                foreach (DataColumn column in dt_docDAY02_GROUPED.Columns)
                {
                    if (column.ColumnName != id)
                        tableJoinedDAY02.Columns.Add(column.ColumnName, column.DataType);
                }

                tableJoinedDAY02.BeginLoadData();

                foreach (DataRow row1 in dt_docDAY01_GROUPED.Rows)
                {
                    foreach (DataRow row2 in dt_docDAY02_GROUPED.Rows)
                    {
                        if (row1.Field<string>(id) == row2.Field<string>(id))
                        {
                            var list = row1.ItemArray.ToList(); // items from table1

                           // add items from table2 except id
                            foreach (DataColumn column in dt_docDAY02_GROUPED.Columns)
                                if (column.ColumnName != id)
                                    list.Add(row2[column]);

                            tableJoinedDAY02.Rows.Add(list.ToArray());
                        }
                    }
                }

                    tableJoinedDAY02.EndLoadData();`

表格1

Account#    |    Day01
1234        |      11
4567        |      22
0909        |      33

表2

Account#    |    Day02
1234        |      12
0909        |      34
5578        |      99
0065        |      34

表3

Account#    |    Day03
1234        |      13
7777        |      44

預期結果合並表

表格1

Account#    |    Day01     |   Day02     |   Day03
1234        |      11      |      12     |     13
4567        |      22      |       0     |     0
0909        |      33      |      34     |     0
5578        |      0       |      99     |     0
0065        |      0       |      34     |     0
7777        |      0       |      0      |     44

@Infost,您正在嘗試執行SQL語言中的full outer join聯接。 在SO上進行搜索時,指向了這個答案https://stackoverflow.com/a/16832096/97471 ,我已將其用於2個以上的表:

從這樣的MVCE開始:

DataTable table1 = new DataTable();
table1.Columns.Add("Account", typeof(int));
table1.Columns.Add("Day01", typeof(decimal));

table1.Rows.Add(1234, 11);
table1.Rows.Add(4567, 22);
table1.Rows.Add(0909, 33);

DataTable table2 = new DataTable();
table2.Columns.Add("Account", typeof(int));
table2.Columns.Add("Day02", typeof(decimal));

table2.Rows.Add(1234, 12);
table2.Rows.Add(0909, 34);
table2.Rows.Add(5578, 99);
table2.Rows.Add(0065, 34);

DataTable table3 = new DataTable();
table3.Columns.Add("Account", typeof(int));
table3.Columns.Add("Day03", typeof(decimal));

table3.Rows.Add(1234, 13);
table3.Rows.Add(7777, 44);

您可以通過以下功能加入他們:

var table123 = FullOuterJoinDataTables(table1, table2, table3);

這是函數源:

DataTable FullOuterJoinDataTables(params DataTable[] datatables) // supports as many datatables as you need.
{
    DataTable result = datatables.First().Clone();

    var commonColumns = result.Columns.OfType<DataColumn>();

    foreach (var dt in datatables.Skip(1))
    {
        commonColumns = commonColumns.Intersect(dt.Columns.OfType<DataColumn>(), new DataColumnComparer());
    }

    result.PrimaryKey = commonColumns.ToArray();

    foreach (var dt in datatables)
    {
        result.Merge(dt, false, MissingSchemaAction.AddWithKey);
    }

    return result;
}

/* also create this class */
public class DataColumnComparer : IEqualityComparer<DataColumn>
{
    public bool Equals(DataColumn x, DataColumn y) { return x.Caption == y.Caption; }

    public int GetHashCode(DataColumn obj) { return obj.Caption.GetHashCode(); }

}

輸出是

Account Day01   Day02   Day03
1234    11      12      13
4567    22
909     33      34
5578            99
65              34
7777                    44

這需要按以下方式處理,所有表不能通過魔術連接在一起,讓我們采用較小的樣本集:

  1. 表1(dt1)-帳戶編號| 第一天
  2. 表2(dt2)-帳戶編號| 第二天
  3. 表3(dt3)-帳戶編號| 第三天
  4. 表4(dt4)-帳戶編號| 第04天
    dt1.AsEnumerable()
    .Join(dt2.AsEnumerable(), d1 => (int)d1["Account#"], d2 =>            
          (int)d2["Account#"],  
          (d1,d2) => new {Account = (int)d1["Account#"],Day01 =  
                     d1["Day01"],Day02 = d2["Day02"]})
    .Join(dt3.AsEnumerable(), d12 => d12.Account, d3 => (int)d3["Account#"],  
      (d12,d3) => new {d12.Account,d12.Day01,d12.Day02,Day03=d3["Day03"]})
    .Join(dt4.AsEnumerable(), dAll => dAll.Account, d4 =>   
          (int)d4["Account#"],  
          (dAll,d4) => new 
         {dAll.Account,dAll.Day01,dAll.Day02,dAll.Day03,Day04=d4["Day04"]})

上述操作的結果將是IEnumerable<AnonymousType> ,其中到目前為止,匿名類型由屬性Account,Day01,Day02,Day03,Day04 ,類似地,您最多可以添加Day31 還要注意,首次發布后我們如何開始使用在最后一個Join語句中生成的AnonymousType

這需要轉換為DataTable ,這類似於以下線程中發布的代碼:

將IEnumerable轉換為DataTable

還要檢查它是否可以使用Nuget實用程序Fastmember使用DataTable using IEnumerable of Anonymous type轉換為DataTable using IEnumerable of Anonymous type

C#如何將IEnumerable匿名列表轉換為數據表

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM