Introducción
La columna de recogida de la tienda ya está ampliada, con counter como valor predeterminado para el cliente antiguo. Los pedidos históricos todavía necesitan sus elecciones aprobadas. Ya han llegado pedidos posteriores: uno omitió la columna nueva y otro eligió explícitamente garden. Una asignación histórica general podría sobrescribir esa elección posterior legítima.
Entregarás backfill.sql y tighten.sql, aplicarás la correspondencia histórica aprobada exacta y conservarás los contratos de ambos clientes. Se requieren los conceptos del laboratorio anterior y SELECT/WHERE y UPDATE básicos; aquí se enseñan los patrones de JOIN, agregación, protección temporal y transacción. Esta unidad independiente de Terminal tiene su propia tabla ampliada, datos y MySQL privado. No se conserva ningún archivo, conexión ni progreso de la VM anterior.
Actualiza únicamente orders.pickup_code para los ID históricos aprobados y endurece las reglas de tipo, valor predeterminado, admisión de null y referencia de esa columna. Conserva las cabeceras originales, las relaciones con los artículos, las elecciones posteriores de recogida, las tablas de aprobaciones y puntos, la tabla de demostración y las herramientas preparadas. Solo se pueden añadir los pedidos de práctica 301 y 302 siguientes. Las solicitudes son secuenciales en una ventana de mantenimiento controlada sin un escritor competidor de aprobaciones. Esto no implementa una migración en línea, coordinación distribuida ni reversión automática de DDL. La estimación de tiempo del autor incluye lectura y errores comunes, sin datos de tiempos de principiantes.
Aplicar solo elecciones históricas aprobadas completas
En este paso, validarás la correspondencia de negocio, guardarás una asignación histórica transaccional y demostrarás que las correspondencias no válidas dejan todos los valores de los pedidos sin cambios.
Empieza en Terminal y entra en este espacio de trabajo independiente:
cd /home/labex/project/pickup-desk
./shop status
./shop map
./shop points
El conjunto histórico es legacy_orders: ID 101, 102 y 103. La correspondencia aprobada indica que 101 va a north, 102 a counter y 103 a garden. Sus totales originales siguen siendo 2100, 3400 y 0. Los dos pedidos de Sam no deben unirse por nombre de cliente. Los ID posteriores 201 y 202 quedan fuera de ese conjunto histórico: conserva 201 en counter y 202 en garden. Sus detalles de artículos también deben conservarse.
Cuenta las filas aprobadas por identidad histórica. COUNT(*) cuenta filas. GROUP BY order_id crea un grupo por ID; HAVING filtra grupos después del recuento. <> significa distinto de. Esta consulta devuelve grupos duplicados o que de otro modo no tienen exactamente una fila:
./db -e "SELECT order_id,COUNT(*) FROM approved_pickups GROUP BY order_id HAVING COUNT(*)<>1;"
Se espera un resultado vacío. No puede revelar un ID completamente ausente, porque una fila ausente no forma ningún grupo. Un LEFT JOIN conserva todas las filas de su izquierda, con campos NULL a la derecha cuando no existe coincidencia. l y m son alias cortos de tabla; ON relaciona ID exactos de pedido. IS NULL selecciona las coincidencias ausentes del lado derecho:
./db -e "SELECT l.order_id FROM legacy_orders l LEFT JOIN approved_pickups m ON m.order_id=l.order_id WHERE m.order_id IS NULL;"
Exige también que cada código de la correspondencia exista en pickup_points y que cada ID de la correspondencia pertenezca a legacy_orders. Un código NULL cuenta como no coincidente en esta comprobación de relación:
./db -e "SELECT m.order_id,m.pickup_code FROM approved_pickups m LEFT JOIN pickup_points p ON p.code=m.pickup_code WHERE p.code IS NULL;"
./db -e "SELECT m.order_id FROM approved_pickups m LEFT JOIN legacy_orders l ON l.order_id=m.order_id WHERE l.order_id IS NULL;"
Las cuatro consultas deberían estar vacías. La correspondencia real preparada es válida y de solo lectura. Una salida de auditoría vacía es una prueba útil, pero un archivo SQL reutilizable también debe rechazar una correspondencia incorrecta en lugar de actualizar a ciegas su subconjunto válido.
Una tabla temporal pertenece a una conexión de base de datos y desaparece cuando esa conexión se cierra. Nuestra pequeña protección almacena únicamente el entero cero: CHECK(errors=0) rechaza un recuento distinto de cero y NOT NULL rechaza un recuento ausente. INSERT ... SELECT COUNT(*) inserta el número de infracciones. Si falla cualquier inserción de protección, el lote nativo se detiene antes del UPDATE de negocio y cierra su conexión. Los cambios de datos pendientes de InnoDB se revierten. ENGINE=InnoDB selecciona el motor de almacenamiento de MySQL con soporte de transacciones para esta tabla temporal. La tabla temporal en sí no es un cambio de esquema permanente reversible. Cada apply o trial inicia una conexión nueva, por lo que no debe reutilizarse ninguna tabla temporal anterior.
Guarda este archivo completo con el here-document entre comillas presentado en el laboratorio anterior. La consulta derivada entre paréntesis, llamada duplicates, convierte sus grupos que no tienen exactamente una fila en filas que un COUNT exterior puede contar. El UPDATE JOIN cambia solo pedidos con un ID exacto aprobado; nunca asigna un valor predeterminado a todos los pedidos. COMMIT hace permanente el cambio de datos solo después de superar las comprobaciones:
cat > backfill.sql <<'SQL'
CREATE TEMPORARY TABLE map_guard (
errors INT NOT NULL CHECK(errors=0)
) ENGINE=InnoDB;
START TRANSACTION;
INSERT INTO map_guard
SELECT COUNT(*) FROM legacy_orders l
LEFT JOIN approved_pickups m ON m.order_id=l.order_id
WHERE m.order_id IS NULL;
INSERT INTO map_guard
SELECT COUNT(*) FROM (
SELECT order_id FROM approved_pickups
GROUP BY order_id HAVING COUNT(*)<>1
) duplicates;
INSERT INTO map_guard
SELECT COUNT(*) FROM approved_pickups m
LEFT JOIN pickup_points p ON p.code=m.pickup_code
WHERE p.code IS NULL;
INSERT INTO map_guard
SELECT COUNT(*) FROM approved_pickups m
LEFT JOIN legacy_orders l ON l.order_id=m.order_id
WHERE l.order_id IS NULL;
UPDATE orders o
JOIN approved_pickups m ON m.order_id=o.order_id
SET o.pickup_code=m.pickup_code;
COMMIT;
SQL
Primero ejercita el archivo guardado en bases de datos nativas desechables. trial ejecuta tu archivo sin cambios con una identidad de migración aislada, con distintos ID históricos y valores. Informa del estado real de salida SQL y de la comparación real de conservación. Nunca edita la correspondencia real ni repara tu SQL. En un caso incorrecto, native_sql_status es distinto de cero mientras accepted es true solo cuando se esperaba ese fallo y todos los valores de negocio permanecieron sin cambios. Esto significa que la prueba verificó correctamente un rechazo, no que la escritura SQL tuviera éxito.
./shop trial backfill.sql good
./shop trial backfill.sql missing
./shop trial backfill.sql duplicate
./shop trial backfill.sql unknown
./shop trial backfill.sql null
./shop trial backfill.sql extra
La prueba good aplica todas las elecciones aprobadas y conserva la recogida explícita posterior. Cada prueba incorrecta informa del error nativo CHECK 3819 y de datos de negocio sin cambios. Estos casos eliminan respectivamente una aprobación, duplican una identidad, usan un punto desconocido, usan NULL o intentan sobrescribir un pedido posterior. Un archivo que siempre falla no puede superar la prueba good. Si una prueba no se acepta, lee su stderr nativo y el motivo, inspecciona cat backfill.sql y corrige el archivo completo. No alteres las herramientas preparadas ni la correspondencia para que la prueba aparezca en verde.
Aplica el mismo archivo original a la correspondencia real válida y lee después cada pedido afectado y protegido:
./shop apply backfill.sql
./shop show 101
./shop show 102
./shop show 103
./shop show 201
./shop show 202
Los códigos históricos son north, counter, garden. El posterior 201 permanece en counter y 202 en garden, con sus notas y detalles intactos. Un esquema rellenado correctamente con valores predeterminados no demostraría por sí solo esas elecciones históricas. Volver a ejecutar esta asignación puramente de datos desde una conexión nueva con la misma correspondencia aprobada sin cambios produce las mismas elecciones; no es permiso para repetir archivos ALTER arbitrarios de una sola ejecución.
Ante ./shopp, usa ls y corrige el nombre de la herramienta. Ante un error de sintaxis, inspecciona y reemplaza el SQL guardado antes de volver a aplicarlo. El lote preparado se detiene en su primer error nativo y se desconecta; no uses --force ni un flujo interactivo SOURCE que continúe después de una comprobación fallida. Esta ventana de mantenimiento controlada excluye ediciones concurrentes de aprobaciones; las consultas separadas de auditoría no son un protocolo general de bloqueo para migraciones concurrentes.
Endurecer la regla sin perder ninguno de los procesos de compra
En este paso, impondrás una referencia de recogida válida y no nula, manteniendo utilizables las escrituras antiguas que omiten la columna y las elecciones nuevas explícitas.
Continúa en Terminal, en /home/labex/project/pickup-desk. La asignación histórica aprobada está completa; inspecciona la definición real:
./db -e "SHOW CREATE TABLE orders;"
La columna todavía admite null y tiene un valor predeterminado explícito counter. NOT NULL rechaza NULL explícito; por sí solo no proporciona un valor predeterminado para un cliente antiguo. Una clave foránea relaciona pickup_code con un pickup_points.code real y único, rechazando códigos desconocidos. RESTRICT impide eliminar o cambiar la identidad de un punto utilizado. Son reglas reales de base de datos, no comprobaciones de una lista desplegable de aplicación.
MODIFY COLUMN vuelve a declarar la definición completa prevista de la columna. Conserva tanto VARCHAR(16) como DEFAULT 'counter' al añadir NOT NULL; los atributos omitidos de MODIFY pueden no conservarse. La coma coloca ambos cambios en una instrucción ALTER. Los nombres de restricciones identifican una regla, pero se aceptan nombres equivalentes. Mantén este DDL fuera de la transacción de asignación histórica: su límite de commit implícito se enseñó en la unidad anterior.
cat > tighten.sql <<'SQL'
ALTER TABLE orders
MODIFY COLUMN pickup_code VARCHAR(16) NOT NULL DEFAULT 'counter',
ADD CONSTRAINT order_pickup_fk FOREIGN KEY(pickup_code)
REFERENCES pickup_points(code)
ON DELETE RESTRICT ON UPDATE RESTRICT;
SQL
./shop apply tighten.sql
./db -e "SHOW COLUMNS FROM orders;"
./db -e "SHOW CREATE TABLE orders;"
Lee pickup_code como NOT NULL con valor predeterminado counter y la referencia a pickup_points(code) con cambios restringidos en el registro padre. Se conservan todos los valores existentes. Ahora crea los dos pedidos de práctica permitidos:
./shop old 301 Mina 1600 MUG 1
./shop new 302 Pia 1900 BAG 2 north
./shop show 301
./shop show 302
La fila real del cliente antiguo almacena counter; la fila real del nuevo almacena north. Sus cantidades de artículos son 1 y 2 y ambas transacciones se confirmaron. El cliente antiguo sigue omitiendo pickup_code; no se ha reescrito a escondidas para proporcionar un valor.
Las dos llamadas siguientes son fallos deliberados y deben terminar con estado distinto de cero. new-null proporciona un NULL SQL real en lugar de omitir el campo. El error nativo 1048 debería rechazarlo. El cliente nuevo normal que proporciona unknown debería recibir el error nativo de clave foránea 1452. Usan el mismo ID sin utilizar porque ninguno de los fallos puede dejar una cabecera ni un artículo:
./shop new-null 399 Invalid 100 MUG 1
./shop new 399 Invalid 100 MUG 1 unknown
./shop show 399
./shop status
Show 399 tiene cabecera y artículos vacíos. Las tres elecciones históricas, los posteriores 201/202 y los recién creados 301/302 permanecen correctos. Un error nativo de base de datos no es una compra vacía correcta ni un problema de conexión. El cliente preparado cierra la transacción fallida; no se necesita reiniciar la VM. Continúa leyendo los pedidos permitidos existentes.
Tu resultado final es el SQL reutilizable de asignación histórica y endurecimiento más el sistema real correcto de pedidos. La evaluación lee este resultado real y prueba el SQL original guardado y la definición actual sobre recursos nativos desechables, incluidas escrituras legítimas y cambios prohibidos en registros padre. No crea un pedido, aplica una migración ni repara un valor ausente en la tienda real.
Si vuelves a ejecutar por accidente un archivo de endurecimiento ya aplicado, la clave foránea con nombre puede existir ya. Inspecciona SHOW CREATE TABLE y conserva la definición válida; no elimines ni vuelvas a crear orders para hacer repetible el script. Un archivo desactualizado debe seguir conteniendo la migración correcta de una sola ejecución desde la fase anterior indicada. El resultado de la ventana de mantenimiento no demuestra DDL sin bloqueos, reversión arbitraria del despliegue, disponibilidad continua de producción ni resistencia a falsificaciones de administradores.
Resumen
Validaste las identidades históricas exactas, rechazaste correspondencias incompletas o ambiguas antes de cambiar valores de negocio y aplicaste una asignación histórica transaccional sin sobrescribir elecciones posteriores de los clientes. El DDL separado de endurecimiento conservó el valor predeterminado del cliente antiguo mientras imponía referencias de recogida válidas y no nulas. Ambas versiones reales del proceso de compra siguen funcionando y las escrituras no válidas fallan de forma nativa.



