Historia de la pregunta:
El SQL estándar fue diseñado originalmente como un lenguaje declarativo sin elementos de programación clásica (bucles, bifurcaciones, saltos directos), sin embargo, con extensiones como T-SQL/PLSQL se han vuelto disponibles construcciones como WHILE, CASE, e incluso la simulación de GOTO.
Problema:
Las operaciones iterativas (bucle que procesa registros uno por uno) a menudo conducen a una disminución del rendimiento, especialmente al procesar grandes volúmenes, si no se reemplazan por un enfoque basado en conjuntos. Las bifurcaciones, CASE, IF — son muy convenientes, pero con una anidación excesiva, la legibilidad y la predictibilidad del código se ven afectadas.
Solución:
El uso de construcciones de control debe estar justificado solo cuando no se puede prescindir del procesamiento por lotes (bulk/set)! Para cálculos complejos — un pequeño bucle, un desencadenador o CASE son aceptables. Para procesamiento masivo — es mejor usar funciones de ventana o UPDATE con subconsultas.
Ejemplo de código (T-SQL):
DECLARE @i INT = 1 WHILE (@i <= 5) BEGIN IF @i % 2 = 0 PRINT CONCAT('Par: ', @i) ELSE PRINT CONCAT('Impar: ', @i) SET @i = @i + 1 END
Expresión CASE:
SELECT num, CASE WHEN num % 2 = 0 THEN 'par' ELSE 'impar' END AS paridad FROM numbers
Características clave:
¿Puede usar CASE para filtrar filas, como WHERE?
¡No! CASE devuelve diferentes valores, pero no filtra filas. Un error común es "filtrar" usando CASE en lugar de WHERE, el resultado será incorrecto.
¿Cuál es la diferencia entre WHILE y CURSOR — no es lo mismo?
WHILE es un bucle básico, con control de variable por el usuario; CURSOR trabaja con las filas de una tabla, manteniendo un enlace a la fila. CURSOR es más intensivo en recursos y a menudo funciona mucho más lento para grandes datos.
¿Cuál enfoque es más rápido para el procesamiento masivo: bucle WHILE con UPDATE o un solo set-based UPDATE?
En el 99% de los casos, un solo UPDATE basado en conjuntos (o INSERT) es significativamente más rápido que un bucle que procesa una sola fila (incluso si parece ser "más flexible").
-- Enfoque incorrecto DECLARE @id INT = 1 WHILE (@id <= 100000) BEGIN UPDATE t SET flag=1 WHERE id=@id SET @id = @id + 1 END -- Correcto UPDATE t SET flag=1 WHERE id BETWEEN 1 AND 100000
En un proyecto para actualizar estados de un millón de pedidos, se escribió un bucle con UPDATE para cada id. El procesamiento tardó ~8 horas. Al fallar a la mitad, se perdía todo, había que corregir manualmente.
Pros:
Contras:
Se modificó a un UPDATE basado en conjuntos con una sola expresión. El tiempo de ejecución se redujo a 6 minutos, el procesamiento es atómico.
Pros:
Contras: