Einführung
Die Abholspalte des Geschäfts ist bereits erweitert, mit counter als Standard für den alten Client. Historische Bestellungen benötigen weiterhin ihre freigegebenen Entscheidungen. Spätere Bestellungen sind bereits eingegangen: Eine hat die neue Spalte ausgelassen, eine hat ausdrücklich garden gewählt. Eine zu breite Datenergänzung könnte diese berechtigte neuere Wahl überschreiben.
Du lieferst backfill.sql und tighten.sql, wendest die exakte freigegebene historische Zuordnung an und bewahrst beide Clientverträge. Voraussetzungen sind die Konzepte des vorherigen Labs sowie grundlegendes SELECT/WHERE und UPDATE; die Muster für JOIN, Aggregation, temporäre Schutzprüfung und Transaktionen werden hier vermittelt. Diese unabhängige Terminal-Einheit hat ihre eigene erweiterte Tabelle, Daten und privates MySQL. Keine Datei, Verbindung oder Fortschritt wird aus der vorherigen VM übernommen.
Aktualisiere nur orders.pickup_code für die freigegebenen historischen IDs und verschärfe Typ-/Standardwert-/NULL-Zulässigkeits-/Referenzregel dieser Spalte. Bewahre ursprüngliche Bestellköpfe, Artikelbeziehungen, spätere Abholentscheidungen, Freigabe-/Abholstellentabellen, Demotabelle und vorbereitete Werkzeuge. Nur die unten angegebenen Übungsbestellungen 301 und 302 dürfen ergänzt werden. Anfragen erfolgen sequenziell in einem kontrollierten Wartungsfenster ohne konkurrierenden Schreiber für Freigaben. Dies implementiert weder Online-Migration noch verteilte Koordination oder automatischen DDL-Rollback. Die Zeitschätzung des Autors umfasst Lesen und gewöhnliche Fehler, ohne Zeitdaten von Anfängern.
Nur vollständige freigegebene historische Entscheidungen anwenden
In diesem Schritt validierst du die geschäftliche Zuordnung, speicherst eine transaktionale Datenergänzung und weist nach, dass ungültige Zuordnungen alle Bestellwerte unverändert lassen.
Beginne in Terminal und wechsle in diesen unabhängigen Arbeitsbereich:
cd /home/labex/project/pickup-desk
./shop status
./shop map
./shop points
Die historische Menge ist legacy_orders: IDs 101, 102 und 103. Die freigegebene Zuordnung sagt, dass 101 zu north, 102 zu counter und 103 zu garden gehört. Ihre ursprünglichen Gesamtbeträge bleiben 2100, 3400 und 0. Die beiden Sam-Bestellungen dürfen nicht anhand des Kundennamens verknüpft werden. Spätere IDs 201 und 202 liegen außerhalb dieser historischen Menge: Bewahre 201 bei counter und 202 bei garden. Auch ihre Artikeldetails müssen erhalten bleiben.
Zähle die freigegebenen Zeilen pro historischer Identität. COUNT(*) zählt Zeilen. GROUP BY order_id erstellt eine Gruppe pro ID; HAVING filtert Gruppen nach dem Zählen. <> bedeutet ungleich. Diese Abfrage gibt doppelte oder anderweitig nicht genau eine Zeile umfassende Gruppen zurück:
./db -e "SELECT order_id,COUNT(*) FROM approved_pickups GROUP BY order_id HAVING COUNT(*)<>1;"
Ein leeres Ergebnis wird erwartet. Es kann keine vollständig fehlende ID aufdecken, weil eine fehlende Zeile keine Gruppe bildet. Ein LEFT JOIN bewahrt jede Zeile auf seiner linken Seite mit NULL-Feldern rechts, wo keine Übereinstimmung existiert. l und m sind kurze Tabellenaliase; ON verknüpft exakte Bestell-IDs. IS NULL wählt fehlende rechtsseitige Übereinstimmungen:
./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;"
Verlange außerdem, dass jeder Zuordnungscode in pickup_points existiert und jede Zuordnungs-ID zu legacy_orders gehört. Ein NULL-Code zählt in dieser Beziehungsprüfung als nicht zugeordnet:
./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;"
Alle vier Abfragen sollten leer sein. Die vorbereitete aktuelle Zuordnung ist gültig und schreibgeschützt. Eine leere Prüfausgabe ist ein nützlicher Beleg, doch eine wiederverwendbare SQL-Datei muss auch eine fehlerhafte Zuordnung ablehnen, statt deren gültige Teilmenge blind zu aktualisieren.
Eine temporäre Tabelle gehört zu einer Datenbankverbindung und verschwindet, wenn diese Verbindung schließt. Unsere kleine Schutzprüfung speichert nur die Ganzzahl 0: CHECK(errors=0) lehnt eine Anzahl ungleich null ab, und NOT NULL lehnt eine fehlende Anzahl ab. INSERT ... SELECT COUNT(*) fügt die Anzahl der Verletzungen ein. Schlägt irgendein Einfügen in die Schutztabelle fehl, hält der native Batch vor dem geschäftlichen UPDATE an und schließt seine Verbindung. Ausstehende InnoDB-Datenänderungen werden zurückgerollt. ENGINE=InnoDB wählt MySQLs transaktionsfähige Speicher-Engine für diese temporäre Tabelle. Die temporäre Tabelle selbst ist keine per Rollback rückgängig zu machende dauerhafte Schemaänderung. Jedes apply oder trial startet eine neue Verbindung, daher muss keine frühere temporäre Tabelle erneut verwendet werden.
Speichere diese vollständige Datei mit dem im vorherigen Lab eingeführten Here-Dokument in Anführungszeichen. Die abgeleitete Abfrage in Klammern namens duplicates wandelt ihre nicht genau eine Zeile umfassenden Gruppen in Zeilen um, die ein äußeres COUNT zählen kann. Das UPDATE JOIN ändert nur Bestellungen mit einer freigegebenen exakten ID; es weist niemals jeder Bestellung einen Standard zu. COMMIT macht die Datenänderung erst dauerhaft, nachdem die Schutzprüfungen erfolgreich waren:
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
Erprobe die gespeicherte Datei zuerst in entbehrlichen nativen Datenbanken. trial führt deine Datei unter einer isolierten Migrationsidentität mit anderen historischen IDs und Werten unverändert aus. Es meldet den tatsächlichen SQL-Exit-Status und den tatsächlichen Vergleich der erhaltenen Daten. Es bearbeitet niemals die aktuelle Zuordnung und repariert dein SQL nicht. In einem fehlerhaften Fall ist native_sql_status ungleich null, während accepted nur dann true ist, wenn dieser Fehler erwartet wurde und jeder geschäftliche Wert unverändert blieb. Das bedeutet, dass der Test eine Ablehnung erfolgreich geprüft hat, nicht, dass der SQL-Schreibzugriff erfolgreich war.
./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
Der gültige Test wendet jede freigegebene Entscheidung an und bewahrt dabei die spätere ausdrückliche Abholwahl. Jeder ungültige Test meldet den nativen CHECK-Fehler 3819 und unveränderte geschäftliche Fakten. Diese Fälle entfernen jeweils eine Freigabe, duplizieren eine Identität, verwenden eine unbekannte Abholstelle, verwenden NULL oder versuchen, eine spätere Bestellung zu überschreiben. Eine immer fehlschlagende Datei kann den gültigen Test nicht bestehen. Wird ein Test nicht akzeptiert, lies sein natives stderr und den Grund, prüfe cat backfill.sql und korrigiere die vollständige Datei. Ändere weder vorbereitete Werkzeuge noch Zuordnung, um den Test grün zu machen.
Wende dieselbe ursprüngliche Datei auf die gültige aktuelle Zuordnung an und lies dann jede betroffene und geschützte Bestellung:
./shop apply backfill.sql
./shop show 101
./shop show 102
./shop show 103
./shop show 201
./shop show 202
Die historischen Codes sind north, counter, garden. Die spätere 201 bleibt counter und 202 bleibt garden, mit intakten Notizen und Details. Ein erfolgreiches, mit Standards gefülltes Schema allein würde diese historischen Entscheidungen nicht beweisen. Diese reine Datenergänzung aus einer neuen Verbindung mit derselben unveränderten freigegebenen Zuordnung erneut auszuführen, erzeugt dieselben Entscheidungen; es ist keine Erlaubnis, beliebige einmalige ALTER-Dateien erneut auszuführen.
Verwende bei ./shopp zuerst ls und korrigiere den Werkzeugnamen. Prüfe und ersetze bei einem Syntaxfehler das gespeicherte SQL vor dem erneuten Anwenden. Der vorbereitete Batch stoppt bei seinem ersten nativen Fehler und trennt die Verbindung; verwende weder --force noch einen interaktiven SOURCE-Ablauf, der nach einer fehlgeschlagenen Schutzprüfung fortfährt. Dieses kontrollierte Wartungsfenster schließt gleichzeitige Freigabeänderungen aus; die separaten Prüf-Abfragen sind kein allgemeines Sperrprotokoll für gleichzeitige Migrationen.
Die Regel verschärfen, ohne einen Checkout zu verlieren
In diesem Schritt erzwingst du einen gültigen Abholverweis ungleich NULL und hältst dabei alte Schreibzugriffe mit ausgelassener Spalte sowie ausdrückliche neue Entscheidungen nutzbar.
Fahre in Terminal unter /home/labex/project/pickup-desk fort. Die freigegebene Datenergänzung ist abgeschlossen; prüfe die aktuelle Definition:
./db -e "SHOW CREATE TABLE orders;"
Die Spalte erlaubt weiterhin NULL und hat einen ausdrücklichen Standardwert counter. NOT NULL lehnt ausdrückliches NULL ab; es liefert einem alten Client allein keinen Standardwert. Ein Fremdschlüssel verknüpft pickup_code mit einem tatsächlichen eindeutigen pickup_points.code und lehnt unbekannte Codes ab. RESTRICT verhindert das Löschen oder Identitätsänderungen einer verwendeten Abholstelle. Dies sind tatsächliche Datenbankregeln, keine Dropdownprüfungen der Anwendung.
MODIFY COLUMN gibt die vollständige beabsichtigte Spaltendefinition erneut an. Bewahre sowohl VARCHAR(16) als auch DEFAULT 'counter', während du NOT NULL ergänzt; bei MODIFY ausgelassene Attribute bleiben nicht unbedingt erhalten. Das Komma setzt beide Änderungen in eine ALTER-Anweisung. Constraint-Namen identifizieren eine Regel, doch gleichwertige Namen werden akzeptiert. Halte dieses DDL außerhalb der Datenergänzungstransaktion: Seine implizite Commit-Grenze wurde in der vorherigen Einheit vermittelt.
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;"
Lies pickup_code als NOT NULL mit Standard counter und den Verweis auf pickup_points(code) mit beschränkten Änderungen übergeordneter Datensätze. Alle vorhandenen Werte bleiben erhalten. Erstelle nun die beiden erlaubten Übungsbestellungen:
./shop old 301 Mina 1600 MUG 1
./shop new 302 Pia 1900 BAG 2 north
./shop show 301
./shop show 302
Die tatsächliche alte Zeile speichert counter; die tatsächliche neue Zeile speichert north. Ihre Artikelmengen sind 1 und 2, und beide Transaktionen wurden per Commit bestätigt. Der alte Client lässt pickup_code weiterhin aus; er wurde nicht heimlich umgeschrieben, um einen Wert zu liefern.
Die nächsten beiden Aufrufe sind absichtliche Fehler und müssen mit einem Status ungleich null enden. new-null liefert tatsächliches SQL NULL, statt das Feld auszulassen. Der native Fehler 1048 sollte dies ablehnen. Der gewöhnliche neue Client mit unknown sollte den nativen Fremdschlüsselfehler 1452 erhalten. Sie verwenden dieselbe unbenutzte ID, weil keiner der Fehler einen Bestellkopf oder Artikel hinterlassen darf:
./shop new-null 399 Invalid 100 MUG 1
./shop new 399 Invalid 100 MUG 1 unknown
./shop show 399
./shop status
Show 399 hat leere Kopf-/Artikelergebnisse. Die drei historischen Entscheidungen, spätere 201/202 und neu erstellte 301/302 bleiben korrekt. Ein nativer Datenbankfehler ist kein erfolgreicher leerer Checkout und kein Verbindungsproblem. Der vorbereitete Client schließt die fehlgeschlagene Transaktion; ein Zurücksetzen der VM ist nicht erforderlich. Fahre mit dem Lesen der vorhandenen erlaubten Bestellungen fort.
Dein endgültiges Ergebnis ist das wiederverwendbare Datenergänzungs-/Verschärfungs-SQL zusammen mit dem tatsächlichen korrekten Bestellsystem. Die Bewertung liest dieses aktuelle Ergebnis und testet das unveränderte gespeicherte SQL sowie die aktuelle Definition auf entbehrlichen nativen Ressourcen, einschließlich zulässiger Schreibzugriffe und verbotener Änderungen übergeordneter Datensätze. Sie erstellt keine Bestellung, wendet keine Migration an und repariert keinen fehlenden Wert im aktuellen Geschäft.
Führst du eine erfolgreiche Verschärfungsdatei versehentlich erneut aus, kann der benannte Fremdschlüssel bereits existieren. Prüfe SHOW CREATE TABLE und bewahre die gültige Definition; entferne/erstelle orders nicht neu, um das Skript erneut ausführbar zu machen. Eine veraltete Datei muss weiterhin die korrekte einmalige Migration aus der angegebenen vorherigen Phase enthalten. Das Ergebnis im Wartungsfenster belegt weder DDL ohne Sperren noch beliebigen Bereitstellungs-Rollback, kontinuierliche Produktivverfügbarkeit oder Widerstandsfähigkeit gegen Administratorfälschungen.
Zusammenfassung
Du hast exakte historische Identitäten validiert, unvollständige oder mehrdeutige Zuordnungen vor dem Ändern geschäftlicher Werte abgelehnt und eine transaktionale Datenergänzung angewendet, ohne spätere Cliententscheidungen zu überschreiben. Getrenntes verschärfendes DDL bewahrte den Standardwert für den alten Client und erzwang zugleich gültige Abholverweise ungleich NULL. Beide tatsächlichen Checkoutversionen funktionieren weiterhin, und ungültige Schreibzugriffe schlagen nativ fehl.



