SQL Server en la práctica

Construir una importación masiva recuperable en SQL Server

Separa carga original, validación y publicación para gestionar archivos inválidos y reintentos sin dejar datos de producción incompletos.

Una carga masiva rápida es solo una parte de una importación fiable. Después hay que explicar qué filas se rechazaron, reconocer archivos ya procesados y evitar que los usuarios vean medio conjunto de datos. Una zona de staging hace explícitas esas responsabilidades.

Conservar la entrada antes de interpretarla

Asigna un identificador estable al lote y conserva identidad del archivo, hash de contenido, llegada y versión del parser. El nombre no basta porque el proveedor puede reutilizarlo con contenido distinto. Guarda campos originales e identificador del registro fuente para rastrear errores.

Carga primero en un área aislada. BULK INSERT necesita una ruta accesible desde el servidor SQL o desde su origen configurado, no desde el portátil del analista. Confirma identidad de acceso y contrato de formato. Prueba codificación, campos vacíos, separadores entre comillas y saltos de línea incrustados.

Una línea física no siempre corresponde a un registro CSV lógico. Si necesitas posiciones exactas, el parser debe conservarlas. Un identity generado en staging no demuestra automáticamente el orden del archivo.

El ejemplo empieza después del parsing y muestra la frontera de validación mediante cadenas originales. No pretende implementar un parser CSV completo.

DECLARE @Raw TABLE
(
    SourceRow int PRIMARY KEY,
    CustomerText nvarchar(100),
    DateText nvarchar(100),
    AmountText nvarchar(100)
);
INSERT @Raw VALUES
(1, N'42', N'20260601', N'125.50'),
(2, N'bad', N'20260602', N'20.00'),
(3, N'43', N'20260230', N'15.00'),
(4, N'44', N'20260603', N''),
(5, N'45', N'20260604', N'-7.00');

SELECT r.*,
    TRY_CONVERT(int, NULLIF(LTRIM(RTRIM(CustomerText)), N'')) AS CustomerId,
    TRY_CONVERT(date, NULLIF(LTRIM(RTRIM(DateText)), N''), 112) AS InvoiceDate,
    TRY_CONVERT(decimal(19,4), NULLIF(LTRIM(RTRIM(AmountText)), N'')) AS Amount
INTO #Parsed
FROM @Raw AS r;

SELECT SourceRow, CustomerId, InvoiceDate, Amount,
    CASE
        WHEN CustomerId IS NULL OR CustomerId <= 0 THEN N'Invalid customer'
        WHEN InvoiceDate IS NULL THEN N'Invalid date'
        WHEN Amount IS NULL OR Amount <= 0 THEN N'Invalid amount'
        ELSE N'Accepted'
    END AS ValidationResult
FROM #Parsed
ORDER BY SourceRow;

DROP TABLE #Parsed;

Solo se acepta la fila 1. La 2 tiene cliente inválido, la 3 fecha imposible, la 4 importe vacío y la 5 importe negativo. NULLIF evita tratar un campo numérico vacío como un número útil. El estilo 112 define YYYYMMDD sin depender del idioma de sesión.

Tratar los rechazos como un resultado

TRY_CONVERT separa muchos fallos de conversión del fallo del lote completo. Una conversión correcta no garantiza validez de negocio. El ejemplo acepta identificadores positivos sin demostrar que el cliente exista. Compruébalos contra el conjunto autorizado antes de publicar.

La conversión a decimal también puede redondear decimales adicionales. Si no está permitido, valida la representación original o compárala con una representación aceptada de mayor precisión. El tipo de destino no sustituye el contrato de entrada.

CASE muestra el primer error por fila para simplificar la lectura. Una tabla de errores real puede guardar varias causas con lote, registro fuente, campo, código y valor original. Define acceso y conservación según los datos. Un mensaje que solo diga 'importación fallida' encarece el soporte.

Busca duplicados dentro del lote y contra la clave de negocio del destino. Decide si significan rechazo, sustitución o agregación deliberada. Usar DISTINCT para evitar una restricción única puede ocultar problemas del proveedor o eliminar diferencias importantes.

Reconcilia cantidades de registros originales, fallos de parsing, rechazos de validación, aceptados y publicados. Define las categorías para no contar varias veces una fila con varios errores. Guarda el resumen con el lote para comprobar integridad sin reabrir el archivo.

Publicar con una frontera de recuperación

Decide si el negocio exige todo o nada o permite aceptación parcial. Para publicación atómica, termina la validación antes de abrir la transacción corta que aplica datos y marca el lote como publicado. Las restricciones finales siguen siendo necesarias porque las referencias pueden cambiar tras la validación.

Exige unicidad para la identidad del lote u operación. Si se pierde la conexión después del commit, el siguiente intento debe consultar el resultado registrado. El marcador de publicación y los cambios deben confirmar juntos.

Los lotes grandes pueden necesitar fragmentos limitados, pero eso modifica la recuperación. Registra los fragmentos completados y haz repetible cada uno, o mantén los datos invisibles hasta un estado final que todos los lectores respeten. Una bandera ignorada por un informe no proporciona esa separación.

Mide conjuntamente parsing, joins de validación, crecimiento del log, mantenimiento de índices y publicación. Conserva los rechazos el tiempo necesario para corregir y reprocesar, y después aplica la política de eliminación. Una importación fiable puede explicar su resultado y reanudarse sin duplicar trabajo.

Referencias técnicas: Microsoft Learn: BULK INSERT · Microsoft Learn: TRY_CONVERT.

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