SQL Server en la práctica

SQL Server OUTPUT: capturar los cambios correctos

Obtenga claves y valores anteriores y nuevos con OUTPUT, considerando orden, desencadenadores, fallos y correlación de reintentos.

Actualizar filas y seleccionarlas después plantea dos preguntas distintas: qué filas cambió la instrucción y qué contienen ahora las filas coincidentes. Bajo concurrencia, las respuestas pueden diferir. OUTPUT vincula el resultado a la propia modificación y permite devolver claves generadas y valores anteriores y nuevos con una relación precisa.

Capturar una correspondencia estable

El ejemplo utiliza tablas temporales y cambia dos filas de inventario. Captura clave, cantidad anterior y cantidad nueva desde el UPDATE. El ORDER BY final define la presentación sin depender del orden físico de modificación.

IF @@TRANCOUNT <> 0
    THROW 50000, 'This example owns its transaction.', 1;
SET XACT_ABORT ON;
CREATE TABLE #Stock (ItemId int PRIMARY KEY, Qty int NOT NULL);
INSERT #Stock VALUES (1, 12), (2, 20);
CREATE TABLE #Changed (ItemId int, OldQty int, NewQty int);
BEGIN TRY
    BEGIN TRAN;
    UPDATE #Stock
    SET Qty = Qty - 2
    OUTPUT inserted.ItemId, deleted.Qty, inserted.Qty
        INTO #Changed(ItemId, OldQty, NewQty)
    WHERE ItemId IN (1, 2) AND Qty >= 2;
    COMMIT;
    SELECT ItemId, OldQty, NewQty FROM #Changed ORDER BY ItemId;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 ROLLBACK;
    THROW;
END CATCH;

Mantenga la clave en el resultado. Devolver únicamente cantidades obliga al cliente a adivinar su correspondencia. En inserciones múltiples, conserve un valor único de correlación del cliente y devuélvalo junto con la identidad generada. No asocie la primera identidad recibida con la primera fila de entrada: ese orden no constituye una garantía.

Capture solo columnas necesarias. OUTPUT inserted.* acopla la API a toda la tabla y puede copiar valores grandes innecesariamente. Una lista explícita hace visibles cambios de tipos y evita exponer campos internos accidentalmente.

Distinguir salida de confirmación

La frontera transaccional sigue siendo decisiva. OUTPUT no acredita que la transacción de negocio haya quedado confirmada. Una instrucción posterior puede fallar, producirse rollback o perderse la conexión durante la respuesta del commit. La aplicación debe consumir el resultado completo y sus errores antes de declarar éxito.

El patrón captura en una tabla temporal, confirma y devuelve filas después. Ante un fallo, CATCH revierte y propaga el error en lugar de devolver una respuesta de éxito. La comprobación impide una transacción exterior, porque el llamador podría todavía revertirla después de recibir el resultado.

Esto resuelve el orden local de respuesta, no una respuesta perdida. Si el commit termina pero el cliente no recibe el resultado, el reintento necesita un identificador persistente para consultar la operación anterior. Una tabla temporal desaparece con la sesión. Guarde correlación y resultado permanentemente cuando la API deba tolerar reintentos de escritura.

Considerar desencadenadores y auditoría

Los valores inserted expuestos por OUTPUT corresponden al cambio antes de ejecutar desencadenadores AFTER. Si uno normaliza un valor, la salida puede diferir del contenido final. Decida qué contrato necesita el cliente. Para valores definitivos, capture claves y diseñe una lectura final con aislamiento apropiado dentro de una transacción bien definida.

La salida directa OUTPUT también tiene restricciones cuando existen desencadenadores activos para la acción. OUTPUT INTO puede ser adecuado, pero su destino tiene limitaciones propias. Revise el esquema real, no solamente una tabla vacía de laboratorio.

Una respuesta al cliente no es una auditoría duradera. Una tabla de auditoría escrita dentro de la misma transacción conserva cambios confirmados, pero su escritura también desaparece al revertir. Registrar intentos fallidos requiere otro diseño. Distinga si necesita cambios exitosos, intentos o ambos.

Finalmente, mida el coste de capturar modificaciones grandes. Millones de valores anteriores y nuevos pueden consumir memoria, log y red. Una respuesta limitada a clave y estado puede ser suficiente. Pruebe éxito, fallo forzado, valores alterados por desencadenadores y correlación de múltiples entradas. Compruebe especialmente que el cliente no trate filas ya recibidas como cambios confirmados cuando posteriormente llega un error de ejecución.

Referencias técnicas: Microsoft Learn: OUTPUT · Microsoft Learn: TRY CATCH.

Pregunta sobre este artículo

¿Tiene alguna pregunta sobre este tema?

Cuéntenos qué está evaluando o dónde tiene dificultades. Le responderemos con una recomendación práctica.

Inquiries are not enabled in this preview.

Hacer una pregunta sobre este artículo