Eine geleerte freiwillige Angabe ist null, nicht die leere Zeichenkette
Some checks failed
CI / Lint, Typen, Tests, Build (push) Successful in 11m49s
CI / Migrationen auf leerer Datenbank (push) Has been cancelled

Beim Speichern in "Daten aendern" brach es ab, sobald bei einer zweiten
Person das Feld "E-Mail (privat)" leer blieb:
duplicate key value violates unique constraint "employees_email_key".

email war bis 20260811140000 NOT NULL -- jede Person hatte eine, das Feld
war nie leer. Seither ist die Angabe freiwillig, aber
change_employee_data schrieb weiter `coalesce(v_person->>'email', email)`.
Ein leeres Formularfeld kommt als "" an, und "" ist nicht null: es landete
als leere Zeichenkette in der Spalte. Beim ersten Mal ging das gut, beim
zweiten schlug der eindeutige Index zu -- "" ist gleich "", waehrend null
nie gleich null ist.

Aufgefallen ist es erst jetzt, weil die Spieldaten durchweg Adressen
trugen. Die 784 uebernommenen Personen tragen keine.

Alle freiwilligen Textfelder bekommen deshalb dieselbe Form wie der
Notfallkontakt und die Firmen-E-Mail: `case when ? then nullif(…, '')`.
Fehlt der Schluessel, bleibt der alte Wert; steht er leer da, wird das
Feld geleert -- die Absicht, die jemand ausdrueckt, wenn er eine Angabe
herausloescht. first_name, last_name, gender, birth_date und nationality
bleiben ausgenommen, sie sind NOT NULL.

Der Nachtlauf bekommt dieselbe Behandlung, sonst liefe eine auf spaeter
datierte Aenderung in denselben Index -- um drei Uhr frueh und ohne
jemanden, dem die Meldung angezeigt wuerde. Was bereits als "" in der
Datenbank steht, raeumt die Migration auf; sonst blockierte diese eine
Zeile weiterhin jede weitere Person ohne Adresse.
This commit is contained in:
2026-09-23 15:42:43 +02:00
parent 948ddf5c70
commit 5e35d6bf41
2 changed files with 506 additions and 4 deletions

View File

@@ -165,12 +165,13 @@ export function DatenAendernPanel({
postal_code: postalCode,
city,
address_country: addressCountry,
email,
// Getrimmt und als leere Zeichenkette durchgereicht: die Datenbank
// macht daraus null, damit sich eine Dienstadresse auch wieder
// entfernen lässt.
// macht daraus null (nullif), damit sich eine Angabe auch wieder
// entfernen lässt. Ungetrimmt käme ein Feld, in dem nur ein
// Leerzeichen stehen geblieben ist, als Inhalt in der Spalte an.
email: email.trim(),
company_email: companyEmail.trim(),
phone,
phone: phone.trim(),
emergency_contact_name: notfallName.trim(),
emergency_contact_phone: notfallTelefon.trim(),
emergency_contact_relation: notfallVerhaeltnis.trim(),