0

同じ列を持つ 2 つのテーブルを結合したいのですが、質問があります。表 1 には、名前、姓の列、およびその他の多くの列があり、表 2 には、名前、コメント、およびその他の多くの列があります。それらを名前列に結合したいので、結果として名前、姓、コメント、およびその他の列にする必要があります。外側の左の Linq を試してみましたが、他にいくつの列があるかわからないため、select new の書き方がわかりません。

私の表1:

Name1   LastName ...
Niki   Row      ...
Hube   Slang    ...
Koke   Mi       ... 
...    ...      ...
...    ...      ...

表 2:

Name  Comment   ...
Koke   "Hello"  ...
Niki   "Hi"     ...

結果は次のようになります。

Name   LastName   Comment ...
Niki    Row        "Hi"   ...
Hube    Sland             ...
Koke    Mi         "Hello"...
...     ...               ...

だから私は行を互いに連結しようとしました。しかし、テーブル 1 の配列はテーブル 2 の配列よりも長いとのことでした。それを結合する別の方法はありますか?

        foreach (DataRow tbE in Table1.Rows)
        {
            foreach (DataRow opT in Table2.Rows)
            {
                if (tbE["Name"].ToString() == opT["Name"].ToString())
                {
                    var row = Result.NewRow();
                    row.ItemArray = tbE.ItemArray
                                       .Concat(opT.ItemArray).ToArray();

                    Result.Rows.Add(row);
                }
                else
                    Result.ImportRow(tbE);

            }
        } 
        Result.Columns.Remove(Name); 
4

2 に答える 2

2

私が最近SOのために別の質問のために最初から書いたこの方法をここで使用することができます(したがって、実際にはテストされていません)。共通のキーで複数のテーブルをマージできます。キーが指定されていない場合は、デフォルトのDataTable.Merge方法が使用されます。

public static DataTable MergeAll(this IList<DataTable> tables, String primaryKeyColumn)
{
    if (!tables.Any())
        throw new ArgumentException("Tables must not be empty", "tables");
    if(primaryKeyColumn != null)
        foreach(DataTable t in tables)
            if(!t.Columns.Contains(primaryKeyColumn))
                throw new ArgumentException("All tables must have the specified primarykey column " + primaryKeyColumn, "primaryKeyColumn");

    if(tables.Count == 1)
        return tables[0];

    DataTable table = new DataTable("TblUnion");
    table.BeginLoadData(); // Turns off notifications, index maintenance, and constraints while loading data
    foreach (DataTable t in tables)
    {
        table.Merge(t); // same as table.Merge(t, false, MissingSchemaAction.Add);
    }
    table.EndLoadData();

    if (primaryKeyColumn != null)
    {
        // since we might have no real primary keys defined, the rows now might have repeating fields
        // so now we're going to "join" these rows ...
        var pkGroups = table.AsEnumerable()
            .GroupBy(r => r[primaryKeyColumn]);
        var dupGroups = pkGroups.Where(g => g.Count() > 1);
        foreach (var grpDup in dupGroups)
        { 
            // use first row and modify it
            DataRow firstRow = grpDup.First();
            foreach (DataColumn c in table.Columns)
            {
                if (firstRow.IsNull(c))
                {
                    DataRow firstNotNullRow = grpDup.Skip(1).FirstOrDefault(r => !r.IsNull(c));
                    if (firstNotNullRow != null)
                        firstRow[c] = firstNotNullRow[c];
                }
            }
            // remove all but first row
            var rowsToRemove = grpDup.Skip(1);
            foreach(DataRow rowToRemove in rowsToRemove)
                table.Rows.Remove(rowToRemove);
        }
    }

    return table;
}

あなたはそれをこのように呼ぶことができます:

var tables = new[] { Table1, Table2 };
tables.MergeAll("Name");

編集:サンプルデータを使用したデバッガーのスクリーンショットは次のとおりです。

ここに画像の説明を入力してください

だからそれは動作します:)

ここでのサンプルデータとテスト:

var Table1 = new DataTable();
var Table2 = new DataTable();
Table1.Columns.Add("Name");
Table1.Columns.Add("LastName");

Table2.Columns.Add("Name");
Table2.Columns.Add("Comment");

Table1.Rows.Add("Niki", "Row");
Table1.Rows.Add("Hube", "Slang");
Table1.Rows.Add("Koke", "Mi");

Table2.Rows.Add("Koke", "Hello");
Table2.Rows.Add("Niki", "Hi");

var tables = new DataTable[] { Table1, Table2 };
DataTable merged = tables.MergeAll("Name");
于 2012-10-31T11:22:10.113 に答える
1

ここに私の貢献のビットがあります。この部分的なコードを使用して、指定された列名で任意の 2 つの DataTable を結合できます。(残りの列を知る必要はありません) 以下にいくつかの機能を示します。

  1. 結果の DataTable には、結合で使用される列の重複はありません。たとえば、「名前」列で結合すると、各テーブルから 1 つのコピーではなく、最後に「名前」列が 1 つだけになります。
  2. 結合で使用されていない重複列の場合、2 番目のテーブルの重複列は末尾に「_2」を追加して名前が変更されます。コードのその部分を変更するだけで、他の方法で動作する可能性があります。
  3. 複数の結合列がサポートされています。この目的のために、LINQ で比較できるように JoinKey クラスが作成されます。
  4. このコードは、オンラインで見つけたコードと私の試行錯誤の混合物のようなものです。私はLINQを初めて使用するので、気軽に批評してください〜

    public class JoinKey
    {
        List<object> objects { get; set; }
    
        public JoinKey(List<object> objects)
        {
            this.objects = objects;
        }
    
        public override bool Equals(object obj)
        {
            if (obj == null || obj.GetType() != typeof(JoinKey))
                return false;
            return objects.SequenceEqual(((JoinKey)obj).objects);
        }
    
        public override int GetHashCode()
        {
            int hash = 0;
            foreach (var foo in objects)
            {
                hash = hash * 31 + foo.GetHashCode();
            }
            return hash;
        }
    }
    
    public enum JoinType
    {
        Inner = 0,
        Left = 1
    }
    
        //Joins two tables and spits out the joined new DataTable. Tables are joined on onCol column names
        //If the right table has column name clashes with the left column, the column names will be appended "_2" and added to joined table
        public static DataTable Join(DataTable left, DataTable right, JoinType joinType, params string[] onCol)
        {
            Func<DataRow, object> getKey = (row) =>
            {
                return new JoinKey(onCol.Select(str => row[str]).ToList());
            };
            var dt = new DataTable(left.TableName);
            var colNumbersToRemove = new List<int>();
            //Populate the columns
            foreach (DataColumn col in left.Columns)
            {
                if (dt.Columns[col.ColumnName] == null)
                    dt.Columns.Add(new DataColumn(col.ColumnName, col.DataType, col.Expression, col.ColumnMapping));
            }
            for (int colIdx = 0; colIdx < right.Columns.Count; ++colIdx)
            {
                var col = right.Columns[colIdx];
                //if this is joined column, it will be removed.
                if (onCol.Contains(col.ColumnName))
                {
                    colNumbersToRemove.Add(colIdx);
                }
                else
                {
                    //if this is duplicate column, it will be renamed.
                    if (dt.Columns[col.ColumnName] != null)
                    {
                        col.ColumnName += "_2";
                    }
                    dt.Columns.Add(new DataColumn(col.ColumnName, col.DataType, col.Expression, col.ColumnMapping));
                }
            }
    
            if (joinType == JoinType.Left)
            {
                var res = from l in left.AsEnumerable()
                          join r in right.AsEnumerable()
                          on getKey(l) equals getKey(r) into temp
                          from r in temp.DefaultIfEmpty()
                          select l.ItemArray.Concat(((r == null) ? (right.NewRow().ItemArray) : r.ItemArray).Minus(colNumbersToRemove)).ToArray();
                foreach (object[] values in res)
                    dt.Rows.Add(values);
            }
            else
            {
                //Inner Join
                var res = from l in left.AsEnumerable()
                          join r in right.AsEnumerable()
                          on getKey(l) equals getKey(r) into temp
                          from r in temp
                          select l.ItemArray.Concat(((r == null) ? (right.NewRow().ItemArray) : r.ItemArray).Minus(colNumbersToRemove)).ToArray();
                foreach (object[] values in res)
                    dt.Rows.Add(values);
            }
            return dt;
        }
    
于 2017-11-30T15:31:47.057 に答える