web-dev-qa-db-fra.com

Jointure interne de DataTables en C #

Soit T1 et T2 sont DataTables avec les champs suivants

T1(CustID, ColX, ColY)

T2(CustID, ColZ)

J'ai besoin de la table commune

TJ (CustID, ColX, ColY, ColZ)

Comment cela peut-il être fait en code C # de manière simple? Merci.

41
Dhana

Si vous êtes autorisé à utiliser LINQ, jetez un œil à l'exemple suivant. Il crée deux DataTables avec des colonnes entières, les remplit avec certains enregistrements, les joint à l'aide de la requête LINQ et les renvoie à la console.

    DataTable dt1 = new DataTable();
    dt1.Columns.Add("CustID", typeof(int));
    dt1.Columns.Add("ColX", typeof(int));
    dt1.Columns.Add("ColY", typeof(int));

    DataTable dt2 = new DataTable();
    dt2.Columns.Add("CustID", typeof(int));
    dt2.Columns.Add("ColZ", typeof(int));

    for (int i = 1; i <= 5; i++)
    {
        DataRow row = dt1.NewRow();
        row["CustID"] = i;
        row["ColX"] = 10 + i;
        row["ColY"] = 20 + i;
        dt1.Rows.Add(row);

        row = dt2.NewRow();
        row["CustID"] = i;
        row["ColZ"] = 30 + i;
        dt2.Rows.Add(row);
    }

    var results = from table1 in dt1.AsEnumerable()
                 join table2 in dt2.AsEnumerable() on (int)table1["CustID"] equals (int)table2["CustID"]
                 select new
                 {
                     CustID = (int)table1["CustID"],
                     ColX = (int)table1["ColX"],
                     ColY = (int)table1["ColY"],
                     ColZ = (int)table2["ColZ"]
                 };
    foreach (var item in results)
    {
        Console.WriteLine(String.Format("ID = {0}, ColX = {1}, ColY = {2}, ColZ = {3}", item.CustID, item.ColX, item.ColY, item.ColZ));
    }
    Console.ReadLine();

// Output:
// ID = 1, ColX = 11, ColY = 21, ColZ = 31
// ID = 2, ColX = 12, ColY = 22, ColZ = 32
// ID = 3, ColX = 13, ColY = 23, ColZ = 33
// ID = 4, ColX = 14, ColY = 24, ColZ = 34
// ID = 5, ColX = 15, ColY = 25, ColZ = 35
50
CZFox

Je voulais une fonction qui joindrait les tables sans vous obliger à définir les colonnes à l'aide d'un sélecteur de type anonyme, mais j'ai eu du mal à en trouver. J'ai fini par devoir faire le mien. J'espère que cela aidera toute personne à l'avenir qui le recherchera:

private DataTable JoinDataTables(DataTable t1, DataTable t2, params Func<DataRow, DataRow, bool>[] joinOn)
{
    DataTable result = new DataTable();
    foreach (DataColumn col in t1.Columns)
    {
        if (result.Columns[col.ColumnName] == null)
            result.Columns.Add(col.ColumnName, col.DataType);
    }
    foreach (DataColumn col in t2.Columns)
    {
        if (result.Columns[col.ColumnName] == null)
            result.Columns.Add(col.ColumnName, col.DataType);
    }
    foreach (DataRow row1 in t1.Rows)
    {
        var joinRows = t2.AsEnumerable().Where(row2 =>
            {
                foreach (var parameter in joinOn)
                {
                    if (!parameter(row1, row2)) return false;
                }
                return true;
            });
        foreach (DataRow fromRow in joinRows)
        {
            DataRow insertRow = result.NewRow();
            foreach (DataColumn col1 in t1.Columns)
            {
                insertRow[col1.ColumnName] = row1[col1.ColumnName];
            }
            foreach (DataColumn col2 in t2.Columns)
            {
                insertRow[col2.ColumnName] = fromRow[col2.ColumnName];
            }
            result.Rows.Add(insertRow);
        }
    }
    return result;
}

Un exemple de la façon dont vous pourriez utiliser ceci:

var test = JoinDataTables(transactionInfo, transactionItems,
               (row1, row2) =>
               row1.Field<int>("TransactionID") == row2.Field<int>("TransactionID"));

Une mise en garde: ce n'est certainement pas optimisé, alors soyez prudent lorsque vous arrivez à un nombre de lignes supérieur à 20k. Si vous savez qu'un tableau sera plus grand que l'autre, essayez de mettre le plus petit en premier et le plus grand une seconde.

29
Bognar

Ceci est mon code. Pas parfait, mais fonctionne bien. J'espère que ça aide quelqu'un:

    static System.Data.DataTable DtTbl (System.Data.DataTable[] dtToJoin)
    {
        System.Data.DataTable dtJoined = new System.Data.DataTable();

        foreach (System.Data.DataColumn dc in dtToJoin[0].Columns)
            dtJoined.Columns.Add(dc.ColumnName);

        foreach (System.Data.DataTable dt in dtToJoin)
            foreach (System.Data.DataRow dr1 in dt.Rows)
            {
                System.Data.DataRow dr = dtJoined.NewRow();
                foreach (System.Data.DataColumn dc in dtToJoin[0].Columns)
                    dr[dc.ColumnName] = dr1[dc.ColumnName];

                dtJoined.Rows.Add(dr);
            }

        return dtJoined;
    }
5
Honza

cette fonction joindra 2 tables avec un champ de jointure connu, mais cela ne peut pas autoriser 2 champs avec le même nom sur les deux tables sauf le champ de jointure, une simple modification serait d'enregistrer un dictionnaire avec un compteur et d'ajouter simplement un numéro au même nom filds.

public static DataTable JoinDataTable(DataTable dataTable1, DataTable dataTable2, string joinField)
{
    var dt = new DataTable();
    var joinTable = from t1 in dataTable1.AsEnumerable()
                            join t2 in dataTable2.AsEnumerable()
                                on t1[joinField] equals t2[joinField]
                            select new { t1, t2 };

    foreach (DataColumn col in dataTable1.Columns)
        dt.Columns.Add(col.ColumnName, typeof(string));

    dt.Columns.Remove(joinField);

    foreach (DataColumn col in dataTable2.Columns)
        dt.Columns.Add(col.ColumnName, typeof(string));

    foreach (var row in joinTable)
    {
        var newRow = dt.NewRow();
        newRow.ItemArray = row.t1.ItemArray.Union(row.t2.ItemArray).ToArray();
        dt.Rows.Add(newRow);
    }
    return dt;
}
1
Yakir Manor

J'ai essayé de le faire de la manière suivante

public static DataTable JoinTwoTables(DataTable innerTable, DataTable outerTable)
        {
            DataTable resultTable = new DataTable();
            var innerTableColumns = new List<string>();
            foreach (DataColumn column in innerTable.Columns)
            {
                innerTableColumns.Add(column.ColumnName);
                resultTable.Columns.Add(column.ColumnName);
            }

            var outerTableColumns = new List<string>();
            foreach (DataColumn column in outerTable.Columns)
            {
                if (!innerTableColumns.Contains(column.ColumnName))
                {
                    outerTableColumns.Add(column.ColumnName);
                    resultTable.Columns.Add(column.ColumnName);
                }                    
            }

            for (int i = 0; i < innerTable.Rows.Count; i++)
            {
                var row = resultTable.NewRow();
                innerTableColumns.ForEach(x =>
                {
                    row[x] = innerTable.Rows[i][x];
                });
                outerTableColumns.ForEach(x => 
                {
                    row[x] = outerTable.Rows[i][x];
                });
                resultTable.Rows.Add(row);
            }
            return resultTable;
        }
0
Antikiller