繁体   English   中英

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

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

我的代码需要帮助。 我有两个具有相同结构的数据表:列和列类型。 不同之处在于某些表格单元格可以为空或填充。 问题是我需要将它们合二为一,如果 null 值将出现在其中一个表中,则将它们替换为现有值,而不创建重复记录。

结构 dt1 EmployeeID|公司|司机姓名|经理|

结构 dt2 EmployeeID|公司|司机姓名|经理|

示例数据:

结构 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

结构 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

预期结果应该是:

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

我在谷歌上搜索并附带了这段代码,但它返回了错误的结果。 我不熟悉 LINQ。 谢谢您的支持!

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();

            }

你的代码几乎可以做你想做的事。 你只需要使用

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"),

代替

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"),

在您的示例中,您将第一个表中的 EmployeeID 和第二个表中的所有其他列设置为结果表。 但是,如果要填充不包括空值的结果表,则必须尝试从第一个表中设置值,如果它们是 null,则从第二个表中设置值。 (有关更多信息,您可以阅读?? 运算符

您还可以根据自己的选择从任何源表中填充结果表,甚至可以使用不同的列作为结果表中 1 列的源。 这是一个例子。

        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();
        }

如果dt1中的记录不在dt2中(反之亦然),则一个连接是不够的。 你必须做一些像完全外连接这样的事情。 我用arrays编写示例,但您可以轻松地将它们替换为DataTable

例子:

\\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