Zbuduj jeden z dwóch danych z pewnymi warunkami

13

Najpierw muszę uzyskać wszystkie dane z ODBC (to już działa).

Potem pojawia się najbardziej skomplikowana część, której nie jestem jeszcze pewien, jak to zrobić. Istnieją dwie tabele danych w ODBC. Łączę je z moim bieżącym kodem i filtruję według określonych parametrów.

Tabela 1 w bazie danych:

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 

Tabela 2 w bazie danych:

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

Scalona tabela danych wygląda następująco:

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 

Jednak scalona tabela danych wyjściowych powinna wyglądać tak (aby mieć możliwość dalszej pracy z nią):

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 

Znajdź duplikaty w NAME. Pozostaw tylko jeden z nich, przypisz numer z Tabeli 1 do NROTabeli 2 do NRO1. Numery z tabeli 1 powinny być podane NRO, numery z tabeli 2 powinny być podane NRO1.

Po połączeniu z ODBC wypełniam jedną tabelę danymi z Tabeli 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);

        }

następnie otrzymuję dane z innej tabeli 2 i łączę je przez:

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

Następnie wykonuję filtrowanie (muszę mieć wiersze zaczynające się od 4 i 1 w NRO, są też wiersze z innym numerem początkowym):

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

Następnie dodaję jeszcze jedną kolumnę dla NRO1(to także dodaje zera (0) Nie potrzebuję ich w kolumnie 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
        }

Za pomocą tego kodu mogę łapać duplikaty

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

ale jak wykonać resztę? Powinno to zostać wykonane przez pętlę z budowaniem nowego stołu? Jak mogę wykonać łączenie i usuwanie duplikatów dataTable?

Kapelusznik
źródło
1. Czy może dataTablezawierać więcej niż dwa duplikaty dla niektórych nazwisk? Na przykład, czy możliwe jest istnienie trzech duplikatów dla BMW? 2. Jak możemy zdefiniować, które z powielonych rekordów zachować, a które usunąć? Na przykład możemy zachować rekord z minimum NROi usunąć drugi rekord.
Iliar Turdushev
@IliarTurdushev 1. datatable nie może zawierać więcej niż jednego „duplikatu” w NAME. Jeśli więcej niż dwa - błąd (moduł obsługi błędów). 2. W moim przykładzie wystąpił błąd, naprawiłem go teraz. Dziękuję, że wspomniałeś o tym, to ważne.
hatman
Czy możesz udostępnić wartości queryStringFI i / lub queryStringSE? Plus jakiego DB używasz?
ATTA
@ATTA Nie mogę zapewnić dostępu do faktycznej bazy danych. Masz na myśli typ DB? Jak czytamy w pytaniu - ODBC
hatman
Właściwie podobało mi się zapytanie, za pomocą którego pobierane są dane, jednak na podstawie kilku założeń napisałem Odpowiedź. Przejrzyj i przekaż swoją opinię. Dzięki
ATTA

Odpowiedzi:

3

Możesz zastąpić merge()wywołanie niestandardową metodą, która jednocześnie scala i filtruje. Zobacz przykład poniżej. Myślę, że jest to lepsze podejście niż pierwsze scalenie (wprowadzenie zduplikowanych wierszy w tabeli wyników), a następnie filtrowanie (tj. Usunięcie zduplikowanych wierszy).

Zakłada się tutaj, że wszystkie parametry mają ten sam format. tTempTabela służy jako tymczasowy przechowywania zawartości tabeli t2, ale z dodatkową kolumnę. Umożliwia to importowanie wierszy w tabeli wyników.

Być może istnieje bardziej eleganckie rozwiązanie, ale powinno działać zgodnie z przeznaczeniem. Pamiętaj, że pominąłem twoje dodatkowe wymagania dotyczące dozwolonych wartości NRO, które z pewnością możesz łatwo dodać.

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
źródło
Dziękuję Ci za to! '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);
Wydaje
Możesz umieścić kod w nowej klasie. Po prostu włóż class Merger {...}mój kod i zadzwoń Merger.merge_it(...). Musisz jednak przygotować parametry wejściowe.
lzydrmr
... i usingoczywiście musisz dodać brakujące dyrektywy. To tylko fragment (z działającego programu).
lzydrmr
Nie jestem pewien, czy wydajność foreacha nad tResult.Select, która może skończyć się bardzo wolno w przypadku większych danych (zakładając, że tResult.Select to O (n), wtedy z foreach spowoduje O (n ^) 2) czas wykonania)
CitrusO2
2

Spróbuj tego:

  1. Uwzględnij pole NRO1 w obu zapytaniach dla tabeli 1 i tabeli 2
  2. Ustaw wartość domyślną 0 NRO1 dla Table1 (zmodyfikuj queryStringSE)

    np .: SELECT NRO, 0 AS NRO1, NAME, NAMEA, NAMEB, ... FROM TABLE1

  3. Ustaw domyślną wartość 0 NRO dla Table2 (zmodyfikuj queryStringFI)

    np .: WYBIERZ 0 JAKO NRO, NRO JAK NRO1, NAZWA, NAMEA, NAMEB, ...... Z TABELI 2

Tabela 1 będzie wyglądać następująco:

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

Tabela 2 będzie wyglądać następująco:

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. Scal tabele, tak jak już to robisz

Dodaj następujące wiersze kodu:

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. Sprawdź „wynik” DataTable pod kątem pożądanych wartości
ATTA
źródło
0

możesz zachować tę samą nazwę kolumny w obu tabelach, jeśli oznaczają one ten sam typ encji, a następnie zobacz ten kod

 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();
    }
}
Jin Thakur
źródło