Wir haben praktisch die selben Grundvorrausetzungen, wie Du (Firebird 2.5, DBExpress, etc...)
Bei uns läuft es so:
In der Datenbank hab ich einen Generator namens "Version". Dieser ist eingentlich nur eine Zahl, die eine Versionsnummer für mich darstellt. Daher weiß ich, welchen Stand die Datenbank hat.
Im Programm habe ich eine Konstante, "Datenbankversion". Diese gibt an, welche Datenbankversion das Programm erwartet.
Beim Start vergleiche ich nun den Wert des Generators mit dem der Konstante.
Fall 1: Generator = Konstante -> Alles in Butter
Fall 2: Generator < Konstante -> Es wird ein Datenbankupdate durchgeführt. Erklär ich gleich.
Fall 3: Generator > Konstante -> Die Datenbank wurde schon mal auf einen höheren Stand konvertiert, als das Programm erwartet (vielleicht auf einem anderen Arbeitsplatz). User davon in Kenntnis setzen und Programm beenden
Das Datenbankupdate läuft so ab.
Erst mal wir gecheckt, ob ich der einzige User bin. Falls nicht, wird der User darüber in Kenntnis gesetzt und gefragt, ob die anderen User rausgeworfen werden sollen (geht seit Firebird 2.5

)
Ich habe den Ist-Stand (Generator) und den Soll-Stand (Konstante). Immer wenn ich eine Änderung an der Datenbank mache während der Entwicklung, kopiere ich das entsprechende DDL-Statement in eine Textdatei. Diese Textdateien liegen in Unterordnern, die durchnummeriert sind.
Hab ich jetzt eine Datenbankversion 3 und das Programm erwartet Version 6, dann weiß ich, ich muss alle Scripte aus den Ordnern 4, 5 und 6 ausführen, um die DB auf den Versionsstand 6 zu bringen.
Wenn ich ein Release mache, setze ich nur die Konstate einen Wert hoch. Und für die nächsten Entwicklungen lege ich einen neuen Unterodner (Nummer + 1) mit einem neuen Script an.
So kann ich aus jedem beliebigen Datenbankstand die DB auf den aktuellen Stand konvertieren. Bei uns gibt es praktisch bei jedem Release eine Datenbankänderung und wir haben locker 20 Releases/Jahr bei rund 600 Usern. Diese Vorgehensweise hat sich als sehr stabil gezeigt.
Die Updateprozeduren sind alle soweit in gekapselt, dass ich sie praktisch ohne Änderung in anderen Produkten einsetzen kann.