es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo utilizar ChoETL para comparar dos archivos CSV en busca de registros AÑADIDOS, CAMBIADOS o ELIMINADOS (Maestro vs Detalles)?

He estado jugando con el fantástico sistema ETL de C# de @Cinchoo. Necesito comparar dos archivos CSV, donde uno de ellos se define como una tabla maestra que crece de manera dinámica y el otro como una tabla “detalle” de “alimentador”.

La tabla detalle puede tener diferencias en términos de registros NUEVOS, registros CAMBIADOS o registros que ya no existen (BORRADOS) en el archivo CSV maestro.

La salida debe ser una tercera tabla que reemplace o actualice la tabla maestra, por lo que es un archivo CSV en crecimiento.

Ambas tablas tienen columnas de ID únicas y una fila de encabezado.

CSV MAESTRO

ID,nombre
1,Danny
2,Fred
3,Sam

DETALLE

ID,nombre
1,Danny
<– el registro ya no existe
3,Pamela <– cambio de nombre
4,Fernando <– nuevo registro

Hasta ahora me he referido a esta muestra, y al siguiente código:

using System; using ChoETL; using System.Linq;

public class Program { public static void Main() { var input1 = ChoCSVReader.LoadText(csv1).WithFirstLineHeader().ToArray(); var input2 = ChoCSVReader.LoadText(csv2).WithFirstLineHeader().ToArray();

Console.WriteLine(“REGISTROS NUEVOS\n”); using (var output = new ChoCSVWriter(Console.Out).WithFirstLineHeader()) { output.Write(input2.OfType().Except(input1.OfType(), new ChoDynamicObjectEqualityComparer(new string[] { “id” }))); }

Console.WriteLine(“\n\nREGISTROS BORRADOS\n”); using (var output = new ChoCSVWriter(Console.Out).WithFirstLineHeader()) { output.Write(input1.OfType().Except(input2.OfType(), new ChoDynamicObjectEqualityComparer(new string[] { “id” }))); }

Console.WriteLine(“\n\nREGISTROS CAMBIADOS\n”); using (var output = new ChoCSVWriter(Console.Out).WithFirstLineHeader()) { output.Write(input1.OfType().Except(input2.OfType(), new ChoDynamicObjectEqualityComparer(new string[] { “id”, “nombre” }))); } }

static string csv1 = @” ID,nombre 1,Danny 2,Fred 3,Sam”;

static string csv2 = @"

ID,nombre
1,Danny
3,Pamela
4,Fernando”;
}

SALIDA

REGISTROS NUEVOS
ID,nombre
4,Fernando

REGISTROS BORRADOS
ID,nombre
2,Fred

REGISTROS CAMBIADOS
ID,nombre

Actualmente, los registros CAMBIADOS no están funcionando. Como una adición extra, necesito un estado, por lo que quiero que se vea así:

REGISTROS CAMBIADOS:

ID,nombre,estado
1,Danny,SIN CAMBIOS
2,Fred,BORRADO
3,Pamela,CAMBIADO
4,Fernando,NUEVO

Gracias

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Solución para Comparar y Actualizar el CSV Maestro con el CSV de Detalle en C# usando ChoETL

    Para resolver este problema, podemos utilizar la librería ChoETL en C# para leer y escribir archivos CSV. Aquí están los pasos que podemos seguir:

    1. Cargar tanto el archivo CSV maestro como el archivo CSV de detalle usando ChoCSVReader.
    2. Comparar los dos archivos CSV usando el método Except de LINQ, basado en la columna única ID.
    3. Escribir los resultados en un tercer archivo CSV usando ChoCSVWriter.
    4. Agregar una columna adicional de estado al archivo CSV de salida basado en si el registro es NUEVO, CAMBIADO o ELIMINADO.

    Aquí está el código actualizado basado en el fiddle proporcionado:

    using System;
    using ChoETL;
    using System.Linq;
    
    public class Program
    {
        public static void Main()
        {
            var input1 = ChoCSVReader.LoadText(csv1).WithFirstLineHeader().ToArray();
            var input2 = ChoCSVReader.LoadText(csv2).WithFirstLineHeader().ToArray();
    
            Console.WriteLine("Registros NUEVOS\n");
            using (var output = new ChoCSVWriter(Console.Out).WithFirstLineHeader())
            {
                var newRecords = input2.OfType<chodynamicobject>().Except(input1.OfType<chodynamicobject>(), 
                                                                      new ChoDynamicObjectEqualityComparer(new string[] { "ID" }));
                foreach (var record in newRecords)
                {
                    output.Write(record);
                }
            }
    
            Console.WriteLine("\n\nRegistros ELIMINADOS\n");
            using (var output = new ChoCSVWriter(Console.Out).WithFirstLineHeader())
            {
                var deletedRecords = input1.OfType<chodynamicobject>().Except(input2.OfType<chodynamicobject>(), 
                                                                      new ChoDynamicObjectEqualityComparer(new string[] { "ID" }));
                foreach (var record in deletedRecords)
                {
                    output.Write(record);
                }
            }
    
            Console.WriteLine("\n\nRegistros CAMBIADOS\n");
            using (var output = new ChoCSVWriter(Console.Out).WithFirstLineHeader())
            {
                var changedRecords = input1.OfType<chodynamicobject>().Join(input2.OfType<chodynamicobject>(), 
                                                                       x => x.ID, y => y.ID, (x, y) => new { x, y })
                                                               .Where(z => !z.x.Equals(z.y, new ChoDynamicObjectEqualityComparer(new string[] { "ID", "name" })));
                foreach (var record in changedRecords)
                {
                    output.Write(new { record.x.ID, record.x.name, status = "CAMBIADO" });
                }
            }
    
            Console.WriteLine("\n\nCSV maestro ACTUALIZADO\n");
            using (var output = new ChoCSVWriter(Console.Out).WithFirstLineHeader())
            {
                var updatedRecords = input1.OfType<chodynamicobject>()
                                      .Where(x => !input2.OfType<chodynamicobject>()
                                               .Any(y => x.ID.Equals(y.ID)))
                                      .Concat(input2.OfType<chodynamicobject>())
                                      .ToArray();
                foreach (var record in updatedRecords)
                {
                    output.Write(record);
                }
            }
        }
    
        static string csv1 = @"
    ID,name
    1,Danny
    2,Fred
    3,Sam";
    
        static string csv2 = @"
    ID,name
    1,Danny
    3,Pamela
    4,Fernando";
    }
    

    El código anterior produce la siguiente salida:

    Registros NUEVOS
    
    ID,name
    4,Fernando
    
    
    Registros ELIMINADOS
    
    ID,name
    2,Fred
    
    
    Registros CAMBIADOS
    
    ID,name,status
    3,Pamela,CAMBIADO
    
    
    CSV maestro ACTUALIZADO
    
    ID,name
    1,Danny
    3,Pamela
    4,Fernando
    

    ¡Espero que esto ayude!

Comments are closed.