C# Запрос Linq, который объединяет две таблицы в одну? - PullRequest
0 голосов
/ 07 апреля 2020

Мне нужна помощь с моим кодом. У меня есть две таблицы данных, которые имеют одинаковую структуру: столбцы и типы столбцов. Разница в том, что некоторые ячейки таблицы могут быть пустыми или заполненными. Проблема заключается в том, что мне нужно объединить их в одно и заменить нулевые значения существующими значениями, если они появятся в одной из таблиц, без создания дублированных записей.

Структура dt1 EmployeeID | Company | Имя драйвера | Manager |

Структура dt2 EmployeeID | Company | Имя драйвера | Manager |

Пример данных:

Структура 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

Я искал в Google и пришел с этим кодом, но он возвращает неправильно результат. Я не знаком с 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();

            }

Ответы [ 2 ]

0 голосов
/ 07 апреля 2020

Если в 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);
0 голосов
/ 07 апреля 2020

Ваш код почти делает то, что вы хотите. Вам нужно только использовать

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 из первой таблицы и все остальные столбцы из второй таблицы в таблицу результатов. Но если вы хотите заполнить таблицу результатов, исключая пустые значения, вам следует попытаться установить значения из первой таблицы, а если они равны нулю, установить значения из вторых таблиц. (Для получения дополнительной информации вы можете прочитать о ?? operator

Вы также можете заполнить свою таблицу результатов из любой исходной таблицы по своему выбору, и вы даже можете использовать разные столбцы в качестве источника для 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();
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...