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.