简体   繁体   English

C# Linq 查询将两个表合并为一个?

[英]C# Linq query which joins two tables in to one?

I need help with my code.我的代码需要帮助。 I have two data tables which have the same structure: columns and column types.我有两个具有相同结构的数据表:列和列类型。 The difference is that some of the table cells can be empty or filled.不同之处在于某些表格单元格可以为空或填充。 The issue is that I need to join them in to one and replace the null values with existing values if they will appear in one of the tables, without creating duplicate records.问题是我需要将它们合二为一,如果 null 值将出现在其中一个表中,则将它们替换为现有值,而不创建重复记录。

Structure dt1 EmployeeID|Company|Driver name|Manager|结构 dt1 EmployeeID|公司|司机姓名|经理|

Structure dt2 EmployeeID|Company|Driver name|Manager|结构 dt2 EmployeeID|公司|司机姓名|经理|

Example data:示例数据:

Structure dt1结构 dt1

EmployeeID|Company|Driver name|Manager  |Manager Email     |HR Admin
000000001 |VW     |John       |Veronica |null              |Lucas
000000002 |Audi   |Monica     |John     |john@john.com     |null
000000003 |Fiat   |Thomas     |Michael  |null              |null

Structure dt1结构 dt1

EmployeeID|Company|Driver name|Manager  |Manager Email     |HR Admin
000000001 |VW     |John       |null     |Veronica@john.com |null
000000002 |null   |Monica     |John     |null              |Martha
000000003 |null   |null       |Michael  |Michael@john.com  |Lucas

Expected result should be:预期结果应该是:

EmployeeID|Company|Driver name|Manager  |Manager Email     |HR Admin
000000001 |VW     |John       |Veronica |Veronica@john.com |Lucas
000000002 |Audi   |Monica     |John     |john@john.com     |Martha
000000003 |Fiat   |Thomas     |Michael  |Michael@john.com  |Lucas

I have searched on google and came with this code but it gives back wrong result.我在谷歌上搜索并附带了这段代码,但它返回了错误的结果。 Im not familiar with LINQ.我不熟悉 LINQ。 Thank you for your support!谢谢您的支持!

try
            {

ErrorMessage = "";
                CollectionOut = new DataTable();
                DataTable dt1 = new DataTable();
                DataTable dt2 = new DataTable();
                            DataTable dt3 = new DataTable();
                            dt3.Columns.Add("EmployeeID", typeof(string));
                            dt3.Columns.Add("Company", typeof(string));
                            dt3.Columns.Add("Driver name", typeof(string));
                            dt3.Columns.Add("Manager", typeof(string));
                            dt3.Columns.Add("Manager Email", typeof(string));
                            dt3.Columns.Add("HR Admin", typeof(string));

                dt3 = (from a in dt1.AsEnumerable()
                       join b in dt2.AsEnumerable() on a.Field<string>("EmployeeID") equals b.Field<string>("EmployeeID")
                       select dt3.LoadDataRow(new object[]
                       {
                            a.Field<string>("EmployeeID"),
                            b.Field<string>("Company"),
                            b.Field<string>("Driver name"),
                            b.Field<string>("Manager"),
                            b.Field<string>("Manager Email"),
                            b.Field<string>("HR Admin"),
                       }, false))
                    .CopyToDataTable();
CollectionOut = dt3;
            }
                catch (Exception ex)
            {
                ErrorMessage = ex.Message.ToString();

            }

Your code is almost do what you want.你的代码几乎可以做你想做的事。 You only need to use你只需要使用

a.Field<string>("EmployeeID"),
a.Field<string>("Company") ?? b.Field<string>("Company"),
a.Field<string>("Driver name") ?? b.Field<string>("Driver name"),
a.Field<string>("Manager") ?? b.Field<string>("Manager"),
a.Field<string>("Manager Email") ?? b.Field<string>("Manager Email"),
a.Field<string>("HR Admin") ?? b.Field<string>("HR Admin"),

instead of代替

a.Field<string>("EmployeeID"),
b.Field<string>("Company"),
b.Field<string>("Driver name"),
b.Field<string>("Manager"),
b.Field<string>("Manager Email"),
b.Field<string>("HR Admin"),

In your example you set EmployeeID from first table and all other columns from second table into result table.在您的示例中,您将第一个表中的 EmployeeID 和第二个表中的所有其他列设置为结果表。 But if you want to fill result table excluding nulls, then you have to try to set values from first table and if they are null, then set values from second tables.但是,如果要填充不包括空值的结果表,则必须尝试从第一个表中设置值,如果它们是 null,则从第二个表中设置值。 (For more info you can read about ?? operator (有关更多信息,您可以阅读?? 运算符

You also can fill your result table from any source table as you choose and you even can use different columns as a source for 1 column in result table.您还可以根据自己的选择从任何源表中填充结果表,甚至可以使用不同的列作为结果表中 1 列的源。 Here is an example.这是一个例子。

        var ErrorMessage = "";
        try
        {
            var CollectionOut = new DataTable();

            //Structure of first datatable
            DataTable dt1 = new DataTable();
            dt1.Columns.Add("EmployeeID", typeof(string));
            dt1.Columns.Add("Company", typeof(string));
            //dt1.Columns.Add("Driver name", typeof(string));
            //dt1.Columns.Add("Manager", typeof(string));
            dt1.Columns.Add("Manager Email", typeof(string));
            dt1.Columns.Add("HR Admin Name1", typeof(string));

            //Structure of second databable
            DataTable dt2 = new DataTable();
            dt2.Columns.Add("EmployeeID", typeof(string));
            dt2.Columns.Add("Company", typeof(string));
            dt2.Columns.Add("Driver name", typeof(string));
            dt2.Columns.Add("Manager", typeof(string));
            //dt2.Columns.Add("Manager Email", typeof(string));
            dt2.Columns.Add("HR Admin Name2", typeof(string));

            //Structure of result datatable
            DataTable dt3 = new DataTable();
            dt3.Columns.Add("EmployeeID", typeof(string));
            dt3.Columns.Add("Company", typeof(string));
            dt3.Columns.Add("Driver name", typeof(string));
            dt3.Columns.Add("Manager", typeof(string));
            dt3.Columns.Add("Manager Email", typeof(string));
            dt3.Columns.Add("HR Admin", typeof(string));

            //Data for example
            dt1.Rows.Add("1", "1", "1", "1", "1", "1");
            dt1.Rows.Add("2", "1", "1", null, "1", "1");
            dt1.Rows.Add("3", "1", "1", "1", null, "1");
            dt2.Rows.Add("1", "1", "1", null, "1", null);
            dt2.Rows.Add("2", "1", "1", "2", "1", "1");
            dt2.Rows.Add("3", "1", "1", "1", "2", "1");

            //Fill result table
            dt3 = (from a in dt1.AsEnumerable()
                         join b in dt2.AsEnumerable() on a.Field<string>("EmployeeID") equals b.Field<string>("EmployeeID") //you join table on your EmployerID here
                         select dt3.LoadDataRow(new object[]
                         {
                             a.Field<string>("EmployeeID"), //result gets EmployeeID from first table
                             a.Field<string>("Company") ?? b.Field<string>("Company"),  //result gets Company from first table, but if it is null then it gets Company from second table
                             b.Field<string>("Driver name"), //result gets Driver name from second table (because we don't have Driver name in first table
                             a.Field<string>("Manager") ?? b.Field<string>("Manager"), //same
                             a.Field<string>("Manager Email"), //result gets Manager Email from first table (because we don't have Manager Email in second table)
                             a.Field<string>("HR Admin Name1") ?? b.Field<string>("HR Admin Name2"), //fil HR Admin column from HR Admin Name1 in 1st table or, if null, from HR Admin Name2 in 2nd table
                         }, false))
                    .CopyToDataTable();
            CollectionOut = dt3;
        }
        catch (Exception ex)
        {
            ErrorMessage = ex.Message.ToString();
        }

If there are records in dt1 that are not in dt2 (Or vice versa) one join is not enough.如果dt1中的记录不在dt2中(反之亦然),则一个连接是不够的。 U must do something like full outer join.你必须做一些像完全外连接这样的事情。 I write example with arrays but u can easily replace them to DataTable我用arrays编写示例,但您可以轻松地将它们替换为DataTable

Example:例子:

\\Helper test class

public class Test
{
   public int Id { get; set; }
   public string A { get; set; }
   public string B { get; set; }
}
var a = new[]
{
    new Test{ Id = 1, A = "AAAAA", B = null },
    new Test{ Id = 2, A = null , B = "BBBB"}
};
var b = new[]
{
    new Test{ Id = 1,  A = null , B = "BBBB" },
    new Test{ Id = 2, A = "AAAAA", B = null },
    new Test{ Id = 3, A = "AAAAA", B = "BBBBB" },
};
var leftOuterJoin =
    from first in a
    join last in b on first.Id equals last.Id into temp
    from last in temp.DefaultIfEmpty()
    select new
    {
        first.Id,
        A = !string.IsNullOrEmpty(first.A) ? first.A : last?.A,
        B = !string.IsNullOrEmpty(first.B) ? first.B : last?.B,
    };

var rightOuterJoin =
    from last in b
    join first in a on last.Id equals first.Id into temp
    from first in temp.DefaultIfEmpty()
    select new
    {
        last.Id,
        A = !string.IsNullOrEmpty(last.A) ? last.A : first?.A,
        B = !string.IsNullOrEmpty(last.B) ? last.B : first?.B,
    };

//fullOuterJoin is result
var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM