Costruisci un datatable su due con determinate condizioni


13

In primo luogo ho bisogno di ottenere tutti i dati da ODBC (questo funziona già).

Poi arriva la parte più complicata che non sono ancora sicuro di come si possa fare. Esistono due tabelle di dati in ODBC. Le sto unendo al mio codice attuale e le sto filtrando con determinati parametri.

Tabella 1 nel database:

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 

Tabella 2 nel database:

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

Dati uniti La tabella è simile alla seguente:

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 

Tuttavia i dati di output uniti La tabella dovrebbe apparire così (per avere la possibilità di lavorarci ulteriormente):

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 

Trova duplicati in NAME. Lasciare solo uno di essi, assegnare un numero dalla Tabella 1 alla NROTabella 2 a NRO1. I numeri della tabella 1 devono essere presenti NRO, i numeri della tabella 2 devono essere presenti NRO1.

Dopo essermi connesso a ODBC, sto compilando una tabella con i dati della tabella 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);

        }

quindi sto ricevendo dati da un'altra Tabella 2 e li unendo per:

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

Dopo di che sto eseguendo il filtraggio (ho bisogno di avere solo righe che iniziano con 4 e 1 in NRO, ci sono anche righe con altro numero iniziale):

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

Quindi sto aggiungendo un'altra colonna per NRO1(questo sta anche aggiungendo zeri (0) non ne ho bisogno nella colonna 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
        }

Posso catturare duplicati con questo codice

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

ma come eseguire il resto? Questo dovrebbe essere eseguito da un ciclo con la costruzione di una nuova tabella? Come posso eseguire l'unione e la rimozione di duplicati dataTable?


1. Può dataTablecontenere più di due duplicati per un nome? Ad esempio, è possibile esistere tre duplicati per BMW? 2. Come possiamo definire quali dei record duplcate conservare e quali eliminare? Ad esempio, possiamo tenere un registro con il minimo NROed eliminare l'altro record.
Iliar Turdushev,

@IliarTurdushev 1. datatable non può contenere più di uno o due "duplicati" in NAME. Se più di due - errore (gestore errori). 2. Nel mio esempio si è verificato un errore, l'ho risolto ora. Grazie per averlo menzionato, è importante.
cappellaio

Puoi condividere i valori di queryStringFI e / o queryStringSE? Inoltre quale DB stai usando?
ATTA

@ATTA Non riesco a fornire l'accesso al database effettivo. Intendi il tipo di DB? Come si legge in questione - ODBC
hatman

In realtà mi è piaciuto vedere la query attraverso la quale vengono recuperati i dati, tuttavia, sulla base di alcuni presupposti che ho scritto Risposta. Si prega di rivedere e dare il tuo feedback. Grazie
ATTA il

Risposte:


3

È possibile sostituire la merge()chiamata con un metodo personalizzato, che esegue l'unione e il filtro contemporaneamente. Vedi l'esempio sotto. Penso che questo sia un approccio migliore rispetto alla prima fusione (introduzione di righe duplicate nella tabella dei risultati) e quindi al filtraggio (ovvero rimozione delle righe duplicate).

Qui, si presume che tutti i parametri abbiano lo stesso formato. La tTemptabella viene utilizzata come memoria temporanea per il contenuto della tabella t2ma con la colonna aggiuntiva. Ciò consente di importare le righe nella tabella dei risultati.

Forse esiste una soluzione più elegante, ma dovrebbe funzionare come previsto. Si noti che ho escluso i requisiti aggiuntivi relativi ai valori consentiti per i NROquali sono sicuro che è possibile aggiungere facilmente.

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

Grazie per questo! Immagino di aver fatto qualcosa di sbagliato come sto ricevendo '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?)dopo aver sostituito dataTable.Merge(newTable);dadataTable.Merge_it(newTable);
hatman il

È possibile inserire il codice in una nuova classe. Metti semplicemente in class Merger {...}giro il mio codice e chiama Merger.merge_it(...). Tuttavia, devi preparare i parametri di input.
lzydrmr

... e devi aggiungere le usingdirettive mancanti , ovviamente. È solo uno snippet (da un programma di lavoro).
lzydrmr

Non sono sicuro delle prestazioni del foreach rispetto a tResult.Select, che potrebbe finire per essere molto lento per i database più grandi (supponendo che tResult.Select sia O (n), quindi con il foreach si otterrà un O (n ^ 2) tempo di esecuzione)
CitrusO2

2

Prova questo:

  1. Includi il campo NRO1 in entrambe le query per Table1 e Table2
  2. Imposta il valore predefinito 0 di NRO1 per Table1 (modifica queryStringSE)

    ad es .: SELEZIONA NRO, 0 COME NRO1, NOME, NAMEA, NOMEB, ... DALLA TABELLA1

  3. Imposta il valore predefinito 0 di NRO per Table2 (modifica queryStringFI)

    es .: SELEZIONA 0 COME NRO, NRO COME NRO1, NOME, NAMEA, NOMEB, ...... DA TABELLA2

La tabella 1 sarà simile a:

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

La tabella 2 sarà simile a:

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. Unisci le tabelle come stai già facendo

Aggiungi le seguenti righe di codice:

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. Controllare DataTable "risultato" per i valori desiderati

0

puoi mantenere lo stesso nome di colonna in entrambe le tabelle se indicano lo stesso tipo di entità, quindi vedi questo codice

 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();
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.