Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Un cursor en SQL permite recorrer el resultado de una consulta y procesarlo fila por fila. A diferencia de una instrucción basada en conjuntos —como un solo UPDATE que cambia todas las filas coincidentes—, un cursor mantiene una posición dentro del resultado y avanza mediante operaciones como FETCH. Es útil cuando cada fila necesita un tratamiento individual, pero no suele ser la primera opción: si la tarea puede expresarse con una consulta basada en conjuntos, esa alternativa suele ser más sencilla y puede ser más eficiente.
Cómo funciona un cursor
Imagina el resultado de una consulta como una lista y el cursor como una marca que indica qué fila toca leer. El cursor combina la consulta, una posición de lectura y un estado de ejecución. Según el motor y el tipo de cursor, el servidor puede conservar ese estado, materializar parte del resultado o gestionarlo de otra manera: no hay una regla universal que diga que siempre copia todas las filas a memoria.
Una consulta SQL suele operar sobre un conjunto completo de filas. Con un cursor, en cambio, el programa obtiene una fila —o un bloque, si el dialecto lo permite—, ejecuta lógica y continúa con la siguiente. Si importa el orden de procesamiento, hay que especificarlo en la consulta con ORDER BY; sin él, no se debe asumir un orden garantizado.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Ciclo habitual: DECLARE, OPEN, FETCH y CLOSE
El flujo conceptual suele ser:
DECLARE → OPEN → FETCH repetido → CLOSE → DEALLOCATE si aplica
DECLARE: define el cursor y la consulta que aportará las filas.OPEN: inicia la lectura y prepara el cursor. No es una instrucción separada en todos los dialectos: en el nivel SQL de PostgreSQL, el cursor queda abierto al declararlo.FETCH: obtiene la siguiente fila, o las filas solicitadas, y desplaza la posición.CLOSE: termina el acceso al cursor y permite liberar recursos asociados.DEALLOCATE: elimina la definición del cursor en motores que tienen esta operación, como SQL Server. No es un paso universal.
La forma de declarar el cursor, detectar que no quedan filas y limpiar recursos depende del motor. No copies un ejemplo de un dialecto en otro sin comprobar sus reglas.
#1 Best Overall
Ejemplo completo en SQL Server
Este ejemplo de Transact-SQL recorre los empleados activos y muestra el identificador y el nombre de cada uno. LOCAL y FAST_FORWARD son opciones de SQL Server, no sintaxis portable a todos los sistemas:
DECLARE empleados_cursor CURSOR LOCAL FAST_FORWARD FOR
SELECT id, nombre
FROM empleados
WHERE activo = 1
ORDER BY id;
DECLARE @id INT;
DECLARE @nombre NVARCHAR(100);
OPEN empleados_cursor;
FETCH NEXT FROM empleados_cursor INTO @id, @nombre;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT CONCAT('Procesando empleado: ', @id, ' - ', @nombre);
FETCH NEXT FROM empleados_cursor INTO @id, @nombre;
END;
CLOSE empleados_cursor;
DEALLOCATE empleados_cursor;
DECLARE asocia el cursor con la consulta. OPEN comienza el recorrido y cada FETCH NEXT coloca los valores de la fila en las variables. En SQL Server, @@FETCH_STATUS = 0 indica que la última operación FETCH obtuvo una fila; cuando no quedan filas, el bucle termina. CLOSE cierra el cursor y DEALLOCATE elimina su definición. FAST_FORWARD solicita un cursor de solo avance optimizado para ese patrón.
En código de producción, asegúrate de cerrar y liberar el cursor también si el procesamiento falla. El mecanismo para manejar excepciones y limpiar recursos debe seguir las convenciones de SQL Server y del procedimiento en el que se ejecuta.
Diferencias entre motores SQL
“Cursor” nombra una idea común, pero no una sintaxis idéntica en todos los productos:
| Motor | Particularidad |
|---|---|
| SQL Server | Usa operaciones como DECLARE CURSOR, OPEN, FETCH, CLOSE y DEALLOCATE. La documentación de Microsoft describe el procesamiento fila por fila y las opciones del producto. |
| PostgreSQL (SQL) | Se declara con DECLARE y se usa con FETCH y CLOSE; en este nivel, la declaración deja abierto el cursor. De forma predeterminada, queda limitado a la transacción. |
| PostgreSQL (PL/pgSQL) | También ofrece variables refcursor y operaciones procedurales como OPEN, FETCH y CLOSE. El contexto importa: el ciclo no es igual al de la interfaz SQL. |
| MySQL | Los cursores se usan dentro de programas almacenados. Son de solo lectura y no desplazables; el final suele detectarse con un CONTINUE HANDLER FOR NOT FOUND. |
| Oracle PL/SQL | El ciclo habitual de un cursor explícito es DECLARE, OPEN, FETCH y CLOSE. El lenguaje también cuenta con cursores implícitos. |
En MySQL, el orden de las declaraciones dentro de un bloque importa: primero se declaran variables y condiciones, después los cursores y, por último, los *handlers*. Su documentación oficial muestra cómo establecer el indicador de fin de resultados con un *handler* NOT FOUND.
PostgreSQL permite declarar cursores desplazables con SCROLL, pero esa capacidad puede tener un coste adicional; además, hay restricciones en ciertos casos, como consultas con bloqueos FOR UPDATE o FOR SHARE. MySQL no admite ese desplazamiento. En PostgreSQL, WITH HOLD permite que un cursor siga disponible tras el fin satisfactorio de la transacción que lo creó; no es una opción universal y puede implicar conservar filas en memoria o en un archivo temporal.
Tipos y capacidades: no todos los cursores hacen lo mismo
- Solo avance o desplazable: un cursor de solo avance recorre filas hacia delante. Uno desplazable puede permitir movimientos como volver a la fila anterior o saltar a otra posición, si el motor y la declaración lo admiten.
- Solo lectura o actualizable: algunos cursores solo leen. En determinados motores y circunstancias, un cursor puede permitir actualizar o borrar la fila actual con operaciones posicionales, como
WHERE CURRENT OF. PostgreSQL documenta esta posibilidad con restricciones; los cursores de MySQL son de solo lectura. - Sensibilidad a cambios: qué modificaciones de datos se ven mientras el cursor está abierto depende del motor, el tipo de cursor y la transacción. No supongas que el resultado es una copia fija ni que siempre refleja cambios posteriores al instante.
También conviene distinguir un cursor en el servidor —por ejemplo, dentro de un procedimiento almacenado— de la forma en que una biblioteca o controlador de una aplicación entrega resultados. Pueden parecerse en el código cliente, pero no necesariamente comparten el mismo ciclo de vida, consumo de recursos o comportamiento transaccional.
Ventajas, costes y duración de la transacción
Un cursor puede ser adecuado cuando cada fila exige una decisión distinta, la lógica depende del estado acumulado o de la fila anterior, hay que invocar una rutina individualmente o se necesitan lecturas controladas. En ciertos entornos también permite entregar resultados de forma progresiva. En cambio, un recorrido fila por fila añade control de estado, detección del final, manejo de errores y limpieza; para cambios uniformes, puede impedir que el motor optimice el trabajo como una sola operación sobre el conjunto.
No todos los cursores son igual de costosos, y una reescritura basada en conjuntos no siempre es posible ni siempre gana sin medir. El rendimiento depende, entre otras cosas, del motor, el volumen, los índices, el plan de ejecución, las transacciones y el trabajo que se realiza en cada iteración. Microsoft advierte que ciertos patrones de cursor pueden convertirse en cuellos de botella; eso no significa que todos los usos sean inadecuados.
Rank #4
Un cursor abierto también puede prolongar el uso de recursos y, según el patrón, la transacción. Un cursor que actualiza filas o usa bloqueos puede afectar a otras sesiones: por ejemplo, Oracle indica que una consulta abierta con FOR UPDATE bloquea las filas de su conjunto de resultados. El impacto exacto depende del motor y del nivel de aislamiento. Mantener transacciones y cursores abiertos más tiempo del necesario puede aumentar contención, retención de bloqueos y uso de almacenamiento temporal.
Cuándo usar un cursor y cuándo evitarlo
Antes de declararlo, comprueba si cada fila realmente requiere un tratamiento diferente. Pregúntate si la tarea puede expresarse con un JOIN, una condición, CASE, una agregación, una función de ventana, una CTE, una tabla temporal o una operación como INSERT ... SELECT. Usa un cursor cuando el requisito secuencial o individual sea real, no solo porque resulte familiar escribir un bucle.
Por ejemplo, si todos los pedidos vencidos y pendientes deben recibir el mismo estado, una operación basada en conjuntos es más directa:
Best Value
UPDATE pedidos
SET estado = 'vencido'
WHERE fecha_limite < CURRENT_DATE
AND estado = 'pendiente';
Un cursor podría recorrer esos pedidos y actualizar uno por uno, pero no aporta una ventaja obvia si la misma regla se aplica a todos. En otros casos, el procesamiento secuencial sí puede estar justificado: una fila puede determinar cómo tratar la siguiente, o cada registro puede requerir una llamada individual que el motor no puede expresar como una transformación de conjunto.
Si el objetivo es mostrar resultados en páginas de una web o API, no confundas cursor con paginación. Un cursor controla cómo se recorre un resultado; la paginación divide la lectura o presentación en páginas independientes. Según el caso, puede convenir paginación por desplazamiento (LIMIT/OFFSET) o por clave (keyset pagination), o procesar los lotes desde la aplicación. La opción adecuada depende de la interfaz, el orden estable que necesites y el volumen.
Quick Recap
Errores frecuentes y cómo prevenirlos
- Copiar sintaxis de otro motor:
@@FETCH_STATUSes propio de SQL Server; PostgreSQL PL/pgSQL puede comprobarFOUNDdespués deFETCH, MySQL suele usar un *handler*NOT FOUNDy Oracle dispone, entre otras opciones, de atributos como%FOUNDy%NOTFOUND. - No detectar el final: el comportamiento al intentar leer después de la última fila varía. Usa el mecanismo de fin de resultados del dialecto en lugar de asumir que siempre habrá otra fila.
- Olvidar la limpieza: cierra el cursor al terminar, incluso tras un error. Si el motor distingue entre cerrar y eliminar la definición, como hace SQL Server con
CLOSEyDEALLOCATE, completa ambos pasos cuando corresponda. - Suponer un orden: si procesar primero una fila y luego otra tiene significado, incluye un
ORDER BYen la consulta del cursor. - Ejecutar consultas adicionales dentro del bucle: hacer un
SELECTo unUPDATEseparado por cada fila puede multiplicar viajes, operaciones y oportunidades de contención. Busca primero una forma de agrupar ese trabajo. - Usar desplazamiento sin necesitarlo: en PostgreSQL,
SCROLLpuede tener un coste y restricciones. Pide navegación hacia atrás solo si el flujo de trabajo la exige. - Dejar abierta una transacción extensa: un cursor no sustituye un plan para limitar la duración de la transacción. Cierra los recursos y termina la transacción cuando el trabajo haya concluido.
Fuentes oficiales para consultar la sintaxis
- Cursores en Transact-SQL (Microsoft Learn) y cursores en SQL Server.
- DECLARE de cursores en PostgreSQL y cursores en PL/pgSQL.
- Cursores en MySQL 8.4.
- Introducción a cursores en Oracle PL/SQL.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →

