Cree una tabla de datos de dos con ciertas condiciones

13

En primer lugar, necesito obtener todos los datos de ODBC (esto ya está funcionando).

Luego viene la parte más complicada de la que todavía no estoy seguro de cómo se puede hacer. Hay dos tablas de datos en ODBC. Los estoy fusionando con mi código actual y los estoy filtrando con ciertos parámetros.

Tabla 1 en la base de datos:

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 

Tabla 2 en la base de datos:

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

DataTable combinado se ve así:

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 

Sin embargo, la tabla de datos de salida combinada debería tener este aspecto (para tener la posibilidad de trabajar más con ella):

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 

Encuentra duplicados en NAME. Deje solo uno de ellos, asigne un número de la Tabla 1 a la NROTabla 2 a NRO1. Los números de la tabla 1 deben estar NRO, los números de la tabla 2 deben estar adentro NRO1.

Después de conectarme a ODBC, estoy llenando una tabla con datos de la Tabla 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);

        }

entonces obtengo datos de otra Tabla 2 y los fusiono de la siguiente manera:

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

Después de eso, estoy realizando el filtrado (necesito tener filas que solo comiencen con 4 y 1 NRO, también hay filas con otro número de inicio):

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

Luego agrego una columna más para NRO1(esto también agrega ceros (0) No los necesito en la columna 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
        }

Puedo atrapar duplicados con este código

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

pero como realizar el resto? ¿Esto debería realizarse mediante un ciclo con la construcción de una nueva tabla? ¿Cómo puedo unir y eliminar duplicados dataTable?

hombre del sombrero
fuente
1. ¿Puede dataTablecontener más de dos duplicados para algún nombre? Por ejemplo, ¿es posible existir tres duplicados para BMW? 2. ¿Cómo podemos definir cuál de los registros duplicados mantener y cuáles eliminar? Por ejemplo, podemos mantener un registro con un mínimo NROy eliminar el otro registro.
Iliar Turdushev
@IliarTurdushev 1. la tabla de datos no puede contener más de uno de dos "duplicados" en NAME. Si hay más de dos: error (controlador de errores). 2. Hubo un error en mi ejemplo, lo he solucionado ahora. Gracias por mencionar este, es importante.
hatman
¿Puede compartir los valores de queryStringFI y / o queryStringSE? Además, ¿qué DB estás usando?
ATTA
@ATTA No puedo proporcionar acceso a la base de datos real. ¿Te refieres al tipo DB? Como se lee en la pregunta - ODBC
hatman
En realidad, me gustó ver la consulta mediante la cual se obtienen los datos, sin embargo, en base a algunas suposiciones que he escrito Respuesta. Por favor revise y dé su opinión. Gracias
ATTA

Respuestas:

3

Puede reemplazar la merge()llamada con un método personalizado, que combina y filtra al mismo tiempo. Vea el ejemplo a continuación. Creo que este es un enfoque mejor que primero fusionar (introducir filas duplicadas en la tabla de resultados) y luego filtrar (es decir, eliminar las filas duplicadas).

Aquí, se supone que todos los parámetros tienen el mismo formato. La tTemptabla se utiliza como almacenamiento temporal para el contenido de la tabla t2pero con la columna adicional. Esto permite importar las filas en la tabla de resultados.

Tal vez haya una solución más elegante, pero esta debería funcionar según lo previsto. Tenga en cuenta que he omitido su requisito adicional con respecto a los valores permitidos para NRO, que estoy seguro de que puede agregar fácilmente.

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
fuente
¡Gracias por esto! Supongo que hice algo mal, ya que estoy recibiendo '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?)después de reemplazar dataTable.Merge(newTable);pordataTable.Merge_it(newTable);
hatman
Podrías poner el código en una nueva clase. Simplemente ponga class Merger {...}mi código y llame Merger.merge_it(...). Sin embargo, debe preparar los parámetros de entrada.
lzydrmr
... y tienes que agregar las usingdirectivas que faltan , por supuesto. Es solo un fragmento (de un programa de trabajo).
lzydrmr
No estoy seguro sobre el rendimiento de foreach sobre tResult.Select, que podría terminar siendo muy lento para tablas de datos más grandes (suponiendo que tResult.Select es O (n), entonces con foreach resultará en O (n ^ ^) 2) tiempo de ejecución)
CitrusO2
2

Prueba esto:

  1. Incluya el campo NRO1 en ambas consultas para Table1 y Table2
  2. Establecer el valor predeterminado 0 de NRO1 para Table1 (modificar queryStringSE)

    por ejemplo: SELECCIONAR NRO, 0 COMO NRO1, NOMBRE, NAMEA, NAMEB, ... DE LA TABLA1

  3. Establecer el valor predeterminado 0 de NRO para Table2 (modificar queryStringFI)

    por ejemplo: SELECCIONE 0 COMO NRO, NRO COMO NRO1, NOMBRE, NAMEA, NOMBREB, ...... DE LA TABLA2

La Tabla 1 se verá así:

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

Table2 se verá así:

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. Combina tablas como ya lo estás haciendo

Agregue las siguientes líneas de código:

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. Verifique el "resultado" de DataTable para los valores deseados
ATTA
fuente
0

puede mantener el mismo nombre de columna en ambas tablas si denotan el mismo tipo de entidad, entonces vea este código

 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
fuente