Построить один набор данных из двух с определенными условиями

13

Во-первых, мне нужно получить все данные из ODBC (это уже работает).

Затем следует самая сложная часть, которую я пока не знаю, как это можно сделать. В ODBC есть две таблицы данных. Я объединяю их с моим текущим кодом и фильтрую по определенным параметрам.

Таблица 1 в базе данных:

NRO   NAME   NAMEA   NAMEB   ADDRESS   POSTA   POSTN   POSTADR   COMPANYN   COUNTRY   ID  ACTIVE
123   Fiat   Punto   500     J5        K4      O3      P4        O2         JT        1   1
133   Opel   Meriva  FTG     J5        K4      O3      P4        O2         JO        3   1
153   MB     E200    C25     JN        KI      OP      PY        OR         JD        5   1
183   BMW    E64     SE0     JR        KE      OT      PG        OL         J8        9   1
103   Audi   S6      700     JP        KU      OU      PN        OH         J6        11  1 

Таблица 2 в базе данных:

NRO   NAME   NAMEA   NAMEB   ADDRESS   POSTA   POSTN   POSTADR   COMPANYN   COUNTRY   ID  ACTIVE
423   Fiat   Punto   500     J5        K4      O3      P4        O2         JT        1   1
463   BMW    E64     SE0     JR        KE      OT      PG        OL         J8        9   1

Объединенная таблица данных выглядит следующим образом:

NRO   NAME   NAMEA   NAMEB   ADDRESS   POSTA   POSTN   POSTADR   COMPANYN   COUNTRY   ID  ACTIVE
423   Fiat   Punto   500     J5        K4      O3      P4        O2         JT        1   1
463   BMW    E64     SE0     JR        KE      OT      PG        OL         J8        9   1
123   Fiat   Punto   500     J5        K4      O3      P4        O2         JT        1   1
133   Opel   Meriva  FTG     J5        K4      O3      P4        O2         JO        3   1
153   MB     E200    C25     JN        KI      OP      PY        OR         JD        5   1
183   BMW    E64     SE0     JR        KE      OT      PG        OL         J8        9   1
103   Audi   S6      700     JP        KU      OU      PN        OH         J6        11  1 

Однако объединенный выходной dataTable должен выглядеть так (чтобы иметь возможность работать с ним дальше):

NRO  NRO1   NAME   NAMEA   NAMEB   ADDRESS   POSTA   POSTN   POSTADR   COMPANYN   COUNTRY   ID  ACTIVE
123  423    Fiat   Punto   500     J5        K4      O3      P4        O2         JT        1   1
133         Opel   Meriva  FTG     J5        K4      O3      P4        O2         JO        3   1
153         MB     E200    C25     JN        KI      OP      PY        OR         JD        5   1
183  463    BMW    E64     SE0     JR        KE      OT      PG        OL         J8        9   1
103         Audi   S6      700     JP        KU      OU      PN        OH         J6        11  1 

Найти дубликаты в NAME. Оставьте только один из них, присвойте номер из таблицы 1, NROиз таблицы 2 - NRO1. Номера таблиц 1 должны быть в NRO, номера таблиц 2 должны быть в NRO1.

После подключения к ODBC я заполняю одну таблицу данными из таблицы 1

        DataTable dataTable = new DataTable("COMPANY");

        using (OdbcConnection dbConnectionSE = new OdbcConnection(connectionStringSE))
        {
            dbConnectionSE.Open();
            OdbcDataAdapter dadapterSE = new OdbcDataAdapter();
            dadapterSE.SelectCommand = new OdbcCommand(queryStringSE, dbConnectionSE);

            dadapterSE.Fill(dataTable);

        }

затем я получаю данные из другой таблицы 2 и объединяю их:

         using (OdbcConnection dbConnectionFI = new OdbcConnection(connectionStringFI))
         {
              dbConnectionFI.Open();
              OdbcDataAdapter dadapterFI = new OdbcDataAdapter();
              dadapterFI.SelectCommand = new OdbcCommand(queryStringFI, dbConnectionFI);

              var newTable = new DataTable("COMPANY");
              dadapterFI.Fill(newTable);

              dataTable.Merge(newTable);
          }

После этого я выполняю фильтрацию (мне нужно, чтобы строки были только с 4 и 1 NRO, есть строки с другим начальным номером):

DataTable results = dataTable.Select("ACTIVE = '1' AND (NRO Like '1%' OR NRO Like '4%')").CopyToDataTable();

Затем я добавляю еще один столбец для NRO1(это также добавляет нули (0), они мне не нужны в столбце NRO1):

        results.Columns.Add("NRO1", typeof(int)).SetOrdinal(1);

        foreach (DataRow row in results.Rows)
        {
            //need to set value to NewColumn column
            row["NRO1"] = 0;   // or set it to some other value
        }

Я могу поймать дубликаты с этим кодом

var duplicates = results.AsEnumerable().GroupBy(r => r[2]).Where(gr => gr.Count() > 1);

а как сделать остальное? Это должно быть выполнено циклом с созданием новой таблицы? Как я могу выполнить объединение и удаление дубликатов dataTable?

hatman
источник
1. Может dataTableсодержать более двух дубликатов для одного имени? Например, возможно ли существование трех дубликатов для BMW? 2. Как мы можем определить, какие из дублирующих записей следует сохранить, а какие удалить? Например, мы можем вести запись с минимумом NROи удалить другую запись.
Ильяр Турдушев
@IliarTurdushev 1. datatable не может содержать более одного «двух дубликатов» в NAME. Если больше двух - ошибка (обработчик ошибок). 2. В моем примере произошла ошибка, сейчас я ее исправил. Спасибо за упоминание этого, это важно.
Hatman
Можете ли вы поделиться значениями queryStringFI и / или queryStringSE? Плюс какую БД вы используете?
ATTA
@ATTA Я не могу предоставить доступ к реальной базе данных. Вы имеете в виду тип БД? Как говорится в вопросе - ODBC
Hatman
На самом деле мне понравилось видеть запрос, по которому выбираются данные, однако, основываясь на нескольких предположениях, которые я написал «Ответ». Пожалуйста, просмотрите и оставьте свой отзыв. Спасибо
ATTA

Ответы:

3

Вы можете заменить merge()вызов пользовательским методом, который выполняет слияние и фильтрацию одновременно. Смотрите пример ниже. Я думаю, что это лучший подход, чем первое слияние (введение повторяющихся строк в таблицу результатов), а затем фильтрация (то есть удаление повторяющихся строк).

Здесь предполагается, что все параметры имеют одинаковый формат. tTempТаблица используются в качестве временного хранилища для содержимого таблицы , t2но с дополнительной колонкой. Это позволяет импортировать строки в таблицу результатов.

Может быть, есть более элегантное решение, но это должно работать как задумано. Обратите внимание, что я исключил ваше дополнительное требование относительно допустимых значений NRO, которое, я уверен, вы можете легко добавить.

static void merge_it(DataTable t1, DataTable t2, DataTable tResult, DataTable tTemp)
    {
        tResult.Merge(t1);
        tResult.Columns.Add("NRO1", typeof(int));

        tTemp.Merge(t2);
        tTemp.Columns.Add("NRO1", typeof(int));

        foreach (DataRow row in tTemp.Rows)
        {
            string name1 = row.Field<string>("NAME");
            string name2 = row.Field<string>("NAMEA");
            DataRow[] matches = tResult.Select($"NAME = '{name1}' AND NAMEA = '{name2}'");
            if (matches.Length > 0)
            {
                matches[0].SetField<int>("NRO1", row.Field<int>("NRO"));
            }
            else
            {
                tResult.ImportRow(row);
            }
        }

        foreach (DataRow row in tResult.Rows)
        {
            if (row["NRO1"] == DBNull.Value)
            {
                row["NRO1"] = 0;
            }
        }
    }
lzydrmr
источник
Спасибо тебе за это! Я думаю, что я сделал что-то не так, как я получаю 'DataTable' does not contain a definition for 'Merge_it' and no accessible extension method 'Merge_it' accepting a first argument of type 'DataTable' could be found (are you missing a using directive or an assembly reference?)после замены dataTable.Merge(newTable);наdataTable.Merge_it(newTable);
Hatman
Вы можете поместить код в новый класс. Просто обведите class Merger {...}мой код и звоните Merger.merge_it(...). Вы должны подготовить входные параметры, хотя.
lzydrmr
... и вы должны добавить недостающие usingдирективы, конечно. Это просто фрагмент (из рабочей программы).
lzydrmr
Я не уверен в производительности foreach по сравнению с tResult.Select, который может оказаться очень медленным для больших таблиц данных (при условии, что tResult.Select равен O (n), тогда с foreach это приведет к O (n ^). 2) время выполнения)
CitrusO2
2

Попробуй это:

  1. Включите поле NRO1 в оба запроса для Table1 и Table2
  2. Установить значение по умолчанию 0 для NRO1 для Table1 (изменить queryStringSE)

    Например: SELECT NRO, 0 AS NRO1, NAME, NAMEA, NAMEB, ... FROM TABLE1

  3. Установить значение по умолчанию 0 для NRO для таблицы 2 (изменить queryStringFI)

    Например: ВЫБЕРИТЕ 0 КАК NRO, NRO AS NRO1, ИМЯ, NAMEA, NAMEB, ...... ИЗ ТАБЛИЦЫ2

Table1 будет выглядеть так:

NRO  NRO1   NAME   NAMEA   NAMEB   ADDRESS   POSTA   POSTN   POSTADR   COMPANYN   COUNTRY   ID  ACTIVE
123   0     Fiat   Punto   500     J5        K4      O3      P4        O2         JT        1   1
133   0     Opel   Meriva  FTG     J5        K4      O3      P4        O2         JO        3   1

Таблица2 будет выглядеть так:

NRO  NRO1   NAME   NAMEA   NAMEB   ADDRESS   POSTA   POSTN   POSTADR   COMPANYN   COUNTRY   ID  ACTIVE
0    423    Fiat   Punto   500     J5        K4      O3      P4        O2         JT        1   1
0    463    BMW    E64     SE0     JR        KE      OT      PG        OL         J8        9   1
  1. Объединяйте таблицы, как вы уже делаете

Добавьте следующие строки кода:

var carGroups = dataTable.AsEnumerable().GroupBy(row => new 
{
   Name = row.Field<string>("Name"),
   NameA = row.Field<string>("NAMEA"),
   NameB = row.Field<string>("NAMEB")
   //Other fields.....
});

DataTable result = dataTable.Clone();

foreach(var grp in carGroups)            
    result.Rows.Add(grp.Sum(r1 => r1.Field<int>("NRO")), grp.Sum(r2 => r2.Field<int>("NRO1")), grp.Key.Name, grp.Key.NameA, grp.Key.NameB);              
  1. Проверьте DataTable «результат» для желаемых значений
АТТА
источник
0

Вы можете сохранить одинаковое имя столбца в обеих таблицах, если они обозначают один и тот же тип объекта, тогда посмотрите этот код

 private static void DemonstrateMergeTable()
{
    DataTable table1 = new DataTable("Items");

    // Add columns
    DataColumn idColumn = new DataColumn("id", typeof(System.Int32));
    DataColumn itemColumn = new DataColumn("item", typeof(System.Int32));
    table1.Columns.Add(idColumn);
    table1.Columns.Add(itemColumn);

    // Set the primary key column.
    table1.PrimaryKey = new DataColumn[] { idColumn };

    // Add RowChanged event handler for the table.
    table1.RowChanged += new 
        System.Data.DataRowChangeEventHandler(Row_Changed);

    // Add ten rows.
    DataRow row;
    for (int i = 0; i <= 9; i++)
    {
        row = table1.NewRow();
        row["id"] = i;
        row["item"] = i;
        table1.Rows.Add(row);
    }

    // Accept changes.
    table1.AcceptChanges();
    PrintValues(table1, "Original values");

    // Create a second DataTable identical to the first.
    DataTable table2 = table1.Clone();

    // Add column to the second column, so that the 
    // schemas no longer match.
    table2.Columns.Add("newColumn", typeof(System.String));

    // Add three rows. Note that the id column can't be the 
    // same as existing rows in the original table.
    row = table2.NewRow();
    row["id"] = 14;
    row["item"] = 774;
    row["newColumn"] = "new column 1";
    table2.Rows.Add(row);

    row = table2.NewRow();
    row["id"] = 12;
    row["item"] = 555;
    row["newColumn"] = "new column 2";
    table2.Rows.Add(row);

    row = table2.NewRow();
    row["id"] = 13;
    row["item"] = 665;
    row["newColumn"] = "new column 3";
    table2.Rows.Add(row);

    // Merge table2 into the table1.
    Console.WriteLine("Merging");
    table1.Merge(table2, false, MissingSchemaAction.Add);
    PrintValues(table1, "Merged With table1, schema added");
}

private static void Row_Changed(object sender, 
    DataRowChangeEventArgs e)
{
    Console.WriteLine("Row changed {0}\t{1}", e.Action, 
        e.Row.ItemArray[0]);
}

private static void PrintValues(DataTable table, string label)
{
    // Display the values in the supplied DataTable:
    Console.WriteLine(label);
    foreach (DataRow row in table.Rows)
    {
        foreach (DataColumn col in table.Columns)
        {
            Console.Write("\t " + row[col].ToString());
        }
        Console.WriteLine();
    }
}
Джин Тхакур
источник