Métodos para gestionar varios casos frecuentes en el desarrollo

Escenario 1: Construir dinámicamente una cláusula SQL IN con una lista de IDs

A menudo necesitamos armar consultas SQL en el backend usando un conjunto de identificadores. Por ejemplo:

IDbConnection connection = null;
StringBuilder sb = new StringBuilder();
var ids = new List<int> { 1, 2, 11, 44, 21, 8, 31, 98 };
sb.Append("SELECT a, b, c, d ");
sb.Append("FROM tablaA LEFT JOIN tablaB ON tablaA.id = tablaB.id ");
sb.Append("LEFT JOIN tablaC ON tablaA.id = tablaC.id ");
sb.Append("WHERE tablaA.id IN (id1, id2, id3) ORDER BY tablaA.fecha");
var result = Dapper.SqlMapper.Query(connection, sb.ToString());

Mostraremos dos formas de convertir la lista en el formato adecuado para la cláusula IN.

Método 1: Método de extensión que recorre la lista

sb.Append("WHERE tablaA.id IN (" + ids.ObtenerCadenaIdsSQL() + ") ORDER BY tablaA.fecha");

Implmeentación del método de extensión:

public static class ExtensionesHelper
{
    public static string ObtenerCadenaIdsSQL(this List<int> listaIds)
    {
        if (listaIds == null || listaIds.Count == 0)
            throw new ArgumentException("La lista de IDs no puede estar vacía.");
        var sb = new StringBuilder();
        listaIds.ForEach(id => sb.Append($"'{id}',"));
        return sb.ToString().TrimEnd(',');
    }
}

Método 2: Usar string.Join directamente

Para IDs numéricos:

sb.Append("WHERE tablaA.id IN (" + string.Join(",", ids) + ") ORDER BY tablaA.fecha");

Si los IDs fueran cadenas, se debe agregar coimllas simples:

sb.Append("WHERE tablaA.id IN ('" + string.Join("', '", ids) + "') ORDER BY tablaA.fecha");

Escenario 2: Clasificación con empates (ranking con saltos)

En reportes empresariales es común necesitar un ranking donde puntuaciones iguales compartan la misma posición y la siguiente posición se calcule según la cantidad de empates. Por ejemplo: si hay 3 estudiantes empatados en el segundo lugar, el siguiente será el quinto.

En lugar de delegar todo el cálculo a la base de datos (lo que puede ser ineficiente con grandes volúmenes), podemos procesar los datos en memoria.

Implementación simple en C#

List<decimal> notas = new List<decimal> { 88, 90, 60, 75, 46, 90, 60, 60 };
var notasOrdenadas = notas.OrderByDescending(n => n).Distinct().ToList();
var dicPosicion = new Dictionary<decimal, int>();
var dicConteo = new Dictionary<decimal, int>();
for (int i = 0; i < notasOrdenadas.Count; i++)
{
    var nota = notasOrdenadas[i];
    int conteo = notas.Count(n => n == nota);
    dicConteo.Add(nota, conteo);
    dicPosicion.Add(nota, i + 1);
}

Console.WriteLine("Ingrese una nota de la lista [88, 90, 60, 75, 46, 90, 60, 60]:");
while (true)
{
    try
    {
        decimal entrada = decimal.Parse(Console.ReadLine());
        int posicionBase = dicPosicion[entrada];
        int ranking = 0;
        if (entrada == notasOrdenadas.Max())
        {
            ranking = 1;
        }
        else if (entrada == notasOrdenadas.Min())
        {
            ranking = notas.Count;
        }
        else
        {
            int acumulado = 0;
            foreach (var nota in notasOrdenadas)
            {
                if (nota != entrada)
                    acumulado += dicConteo[nota];
                else
                {
                    acumulado += 1;
                    break;
                }
            }
            ranking = acumulado;
        }
        Console.WriteLine($"El ranking de {entrada} es: {ranking}");
    }
    catch
    {
        Console.WriteLine("Error, intente de nuevo.");
    }
    System.Threading.Thread.Sleep(90);
}

Esta lógica se puede integrar en una API o servicio. Por ejemplo, en un endpoint de Postman se obtienen los datos en ~325 ms, lo cual es aceptable.

Etiquetas: C# SQL Dapper ranking manejo de colecciones

Publicado el 7-17 06:29