Datenbankstruktur überprüfen und abgleichen

B

BartTheDevil89

Guest
Hallo,

also ich habe ein Problem, bzw. eine Frage. Und zwar möchte ich eine Datenbank überprüfen können. Ich habe zum Beispiel Tabelle1 mit den und den Spalten. Dann Tabelle 2 mit den und den Spalten....etc.
Jetzt suche ich irgendwie ne Möglichkeit diese zu überprüfen. Also ich speichere in einer Datei in irgendeiner Form (welche?) wie die Tabellen alle ausschauen müssten. Dann möchte ich die Struktur in der Datei mit der in der Datenbank abgleichen und wenn in der Datei was anders ist als in der DB, soll er die DB eben an die Version der Datei anpassen. Also kann ja drei Fälle geben:
1. Es ist alles gleich -> es wird eben nichts geändert
2. irgendwie ist ein Struktur in der Datenbank falsch -> wird an die Datei angepasst
3. In der DAtei ist was neu -> wird in die Datenbank auch mit eingebaut.

Bzw. ansonsten gibts ne Möglichkeit folgende Abfrage zu machen? Ich habe einen Tabellennamen und überprüfe, ob die vorhanden ist. Wenn nein, dann soll er die erstellen.
Als zweites dann überprüfen, ob Spalte1 mit den eigenschaften vorhanden ist. Wenn nein, dann erstellen, wenn ja, dann die Eigenschaften der Tabelle erstellen und wenn die nicht passen, dann diese ändern.

Aber jetzt die Frage: Wie schaffe ich es so ein System zu erstellen? Also sowohl in welcher Form sollte ich das abspeichern in der Datei und wie muss dann die Funkion zum Abgleich ausschauen?

Danke für eure Hilfe
 
QUOTE (BartTheDevil89 @ Fr 8.08.2008, 08:20) Bzw. ansonsten gibts ne Möglichkeit folgende Abfrage zu machen? Ich habe einen Tabellennamen und überprüfe, ob die vorhanden ist. Wenn nein, dann soll er die erstellen.

Und woher kennt er die dazugehörige Tabellenstruktur, Datentypen, Keys, Indexe etc..? Da müsstest du noch fast irgendwo die ganzen Metadaten aufbauen/ablegen.

Mal abgesehen davon wie vernüntig dieses Konzept ist, würde man sowas vermutlich am besten mit einem ETL-Tool erledigen. Sieh dir dazu mal die Produkte PDI/Kettle oder Talend an.

Dynamisch Änderungen an der Datenbankstruktur zu machen würde ich aber in jedem Fall unterlassen!
 
So unvernünftig ist so eine Logik nicht. Jemand, der etwas ähnliches wie server-daten anbietet, nutzt so etwas, um dann aus den Textdateien heraus die Tabellen automatisiert zu generieren bzw. zu ändern. Innerhalb von server-daten ist das im Rahmen der Tabellenerstellung / Bearbeitung implementiert. Die Daten werden eben nicht in einer Textdatei, sondern ebenfalls in Tabellen abgelegt, eine Datenbank gibt es ja ohnehin.

Grundsätzlich benötigt man so etwas für die Implementierung eines "Don't Repeat Yourself" - Prinzips, wie es bsp. auch laut diesem Artikel in Ruby on Rails drin ist: Informationen werden nur an einer Stelle abgelegt. Der Webserver kann dann dieselben Informationen nutzen, um gespeicherte Prozeduren mit Parametern zu bestücken, damit Insert/Update/Delete zu erledigen - und schon hat man kaum mehr Probleme mit Sql-Injektionen.

Nur: Das ist eine Arbeit von einigen Wochen, Monaten oder noch länger.

Dateiformat definieren, Lese- und Schreibroutinen, eine 'Vergleichsüberprüfung', welche die auszuführenden Befehle generiert, anschließend diese ausführen.

Tabellen kann man auch dynamisch ändern - allerdings würde ich das nur auf einem System machen, das Transaktionen unterstützt. Dann kann man das innerhalb einer Transaktion machen.
 
Wenn du unbedingt die Daten in einer Datei speichern willst, würde ich für jede Spalte eine eigene Datei anlegen und jede neue Tabelle in einem neuen Ordner.

Sonst kann der Dateinhalt unübersichtlich werden, insbesondere, wenn die Datensätze strings beinhalten.

Dann liest du die Ordnernamen in ein Array und vergleichst mit den Tabellen.
mysql_list_tables()

Falls eine Tabelle noch nicht erstellt ist, musste die diese halt erzeugen.

Wenn die Tabelle vorhanden ist, liest du deine Spalten-Dateiennamen aus dem Ordner in ein Array und vergleichst mit den Tabellenspalten.
mit mysql_num_fields() die Anzahl Spalten vergleichen oder mysql_list_fields() die Spalten lesen.

dann wie gehabt:
Falls eine Spalte noch nicht erstellt ist, musste die diese halt erzeugen.

Wenn die Spalte vorhanden ist, liest du deine Spalten-Dateiennamentabelle Zeile für Zeile und vergleichst mit den Tabellenspaltendaten oder schaust einfach ob die Spalte genauso gross ist wie die Datei.

Entweder kannst du dann zum Abschluss alle neuen Datensätze einfügen oder gleich nach dem Erzeugen.

Mein Webcounter funktioniert zur Datenkomprimierung so ähnlich und macht ein monatliches Update. Allerdings werden Datenbanken mit Datenbanken und Tabellen mit Tabellen abgeglichen.

mysql wird nach Überschreiten der Grenze von ca. 1000 Tabellen etwas langsamer.
Gleiches gilt für die Anzahl Spalten, habe ich irgendwo in Erinnerung.

Die Funktion ist sehr zeitaufwendig, du solltest also unbedingt wie J.Auer bereits erwähnte Transaktionen benutzen und dafür sorgen, dass der Server über ein genügend grosses Zeitfenster zum Ausführen verfügt. ( connection timeout )

Auf php.net sind die gängigsten mysql-Funktionen


Grüsse

Tümmel

ps. Das ist eine ziemlich langweilige und aufwendige Fleissarbeit. Wenn nicht irgendwie anders geht, würde ich es lassen.

 
QUOTE (Tuemmel @ Fr 8.08.2008, 22:57)Die Funktion ist sehr zeitaufwendig, du solltest also unbedingt wie J.Auer bereits erwähnte Transaktionen benutzen und dafür sorgen, dass der Server über ein genügend grosses Zeitfenster zum Ausführen verfügt. ( connection timeout )

Wenn man für jede Tabelle die Daten erst nach PHP exportiert und eine parallele Struktur als Verzeichnis erzeugt, dann ist das auch irre aufwendig.

U.a. deshalb würde ich das direkt in der Datenbank machen. Dann sind das zwei Tabellen (eine für Tabellen, eine für Spalten) und man kann mit einem Cursor (gibts inzwischen auch bei mySql) die Daten einmal holen und der Reihe nach abarbeiten.

Beim MS-SqlServer gibt es eine schöne Technik, die ich vor 5 Jahren mal in einem Artikel (Sql-Befehl als Sysadmin ohne Recht) beschrieben hatte: Der Webserver setzt bloß (mit sehr niedrigen Rechten ausgestattet) einen 'benutzerdefinierten Fehlerwert' (das Wort 'Fehler' ist in diesem Zusammenhang irreführend). Das wird als Warnung registriert, diese löst den Job aus - der nun mit höheren Rechten die eigentliche Aktion ausführt. Und da das db-server-intern ist, gibt es auch kein Problem mit Scriptlaufzeiten.

Damit kann der Webserver über eine sehr schwache Verbindung 'starke Aktionen' auslösen. Selbst ein komplett gehackter Webserver, bei dem der Hacker interaktiv über diese Verbindung an der Datenbank sitzt, könnte nicht mehr machen.
 
Puh, scheint ja verdammt aufwendig zu sein. Dann mal so ne Frage:

Gibts ne Möglichkeit folgende Abfrage zu machen?

1. Ich habe einen Tabellennamen und überprüfe, ob die vorhanden ist. Wenn nein, dann soll er die erstellen.
2. Als zweites dann überprüfen, ob Spalte1 mit den eigenschaften vorhanden ist. Wenn nein, dann erstellen, wenn ja, dann die Eigenschaften der Tabelle überprüfen und wenn die nicht passen, dann diese ändern.

Denn dann würde ich die Tabellennamen und die Spaltennamen inkl. Eigenschaften in ner Datei(XML oder so) speichern und auslesen. Und dann eben die Sachen oben prüfen.
 
Das

QUOTE (BartTheDevil89 @ Sa 9.08.2008, 21:36)Gibts ne Möglichkeit folgende Abfrage zu machen?

1. Ich habe einen Tabellennamen und überprüfe, ob die vorhanden ist. Wenn nein, dann soll er die erstellen.
2. Als zweites dann überprüfen, ob Spalte1 mit den eigenschaften vorhanden ist. Wenn nein, dann erstellen, wenn ja, dann die Eigenschaften der Tabelle überprüfen und wenn die nicht passen, dann diese ändern.

Denn dann würde ich die Tabellennamen und die Spaltennamen inkl. Eigenschaften in ner Datei(XML oder so) speichern und auslesen. Und dann eben die Sachen oben prüfen.


ist die Hauptarbeit.

Das dann statt über eine Spalte über viele oder statt bloß über eine Tabelle über viele Tabellen laufen zu lassen ist banale Schleifentechnik. Aber die ganze Arbeit steckt in diesem inneren Schritt. Für den braucht man bereits alles, was Arbeit macht.

Und ja, das ist aufwendig.

Mir ist nicht klar, was Du damit machen willst, ob das vielleicht viel einfacher geht. Aber das ist nun einmal einer der innersten Kerne von solchen Angeboten wie server-daten und analogen Angeboten.

Und das hat nun mal auch diverse Sicherheitsimplikationen. Wer an diese Daten rankommt (etwa, wenn das als Datei auf dem Webserver gespeichert wird und jemand mit PHP-Fileoperationen diese Dateien ändern kann), der kommt eben auch an die eigentlichen Daten ran. Der baut sich dann über so einen Kanal eigene Tabellen auf. Die Logindaten werden auch bei server-daten nicht über so einen Weg verwaltet, wäre ja Wahnsinn. Sprich: Du mußt auch dafür sorgen, daß man auf bestimmte Tabellen so nicht zugreifen kann.
 
QUOTE (BartTheDevil89 @ Sa 9.08.2008, 22:36) Puh, scheint ja verdammt aufwendig zu sein. Dann mal so ne Frage:

Gibts ne Möglichkeit folgende Abfrage zu machen?

1. Ich habe einen Tabellennamen und überprüfe, ob die vorhanden ist. Wenn nein, dann soll er die erstellen.
2. Als zweites dann überprüfen, ob Spalte1 mit den eigenschaften vorhanden ist. Wenn nein, dann erstellen, wenn ja, dann die Eigenschaften der Tabelle überprüfen und wenn die nicht passen, dann diese ändern.

Denn dann würde ich die Tabellennamen und die Spaltennamen inkl. Eigenschaften in ner Datei(XML oder so) speichern und auslesen. Und dann eben die Sachen oben prüfen.

Ich hab auch die Problematik das ich Tabellen habe die ich um Spalten erweitern will .... dafor muß geprüft werden ob die Spalte schon vorhanden ist ....

vorhanden?
nein = ALTER TABLE insert spalte .... ist noch leicht

Eine Spalte zu prüfen "wie und was und so ..." wird dann vielviel schwerer



CODE



$BASENAME='Datenbankname';
$TABLES_IN_DB='Tables_in_'.$BASENAME;

$TABLEFOUND=0;
$TABLESEARCH='is sie schon drin in der DB';
$result= mysql_query(" SHOW TABLES") or die('<hr>'.$query.'</hr>'.mysql_error());
while( $line= mysql_fetch_array($result, MYSQL_ASSOC))
{
if ( $line[$TABLES_IN_DB]==$TABLESEARCH ) $TABLEFOUND=1;
}
if ( $TABLEFOUND )
{
// bum bum Boris .....
}
else
{
$query ="
CREATE TABLE `$TABLESEARCH` (
`lid` int(11) NOT NULL auto_increment,
`ts` int(11) default '1',
`flags` int(11) default '0',
`artikel` varchar(230) default NULL,
`titel` varchar(255) default NULL,
PRIMARY KEY (`lid`)
) TYPE=MyISAM;";
mysql_query($query) or die('<hr>'.nl2br($query).'<hr>'.mysql_error());
// jetzt bist du drin ....
}


das sollte jetzt aber besser als "function" abgelegt werden und die "TABLESEARCH" eben als $para für die function .... und den $CREATE auch, damit die function für "alle" Tabellen(unterschiedlichen) ....

für die Spalten hab ich bisher nur einen "mal reinschauen" Code in Use

CODE
$TABLESEARCH='is sie schon drin in der DB';

$query = " SHOW COLUMNS FROM " . $TABLESEARCH;
echo('<hr>'.$query.'<hr>');
$result= mysql_query($query) or die('<hr>'.$query.'<hr>'.mysql_error());
while( $line= mysql_fetch_array($result, MYSQL_ASSOC))
{

foreach ($line as $key => $value) {
echo "\n<br><b>$key</b> $value";}
echo('<br>»»');
}

 
QUOTE 2. Als zweites dann überprüfen, ob Spalte1 mit den eigenschaften vorhanden ist.


Das klingt ja scheusslich. Entweder ist Spalte1 vorhanden und sollte dann auch die entsprechenden Eigenschaften besitzen oder die Spalte ist noch nicht vorhanden und sollte hinzugefügt werden. Strukturen von Spalten zu verändern, die schon mit Daten belegt sind, ist immer riskant. Jedenfalls erhälst du mit mysql_fetch_field() ein Array mit den Spalteneigenschaften.
Meinetwegen zum Beispiel mit :

$meta=mysql_fetch_field($spalte,$i);
if( $meta->type =='string'){
mysql_query('ALTER TABLE `'.$table_list[0].'` CHANGE `'.$meta->name.'` `'.$meta->name.'` VARCHAR( '.$len.' ) CHARACTER SET utf8 COLLATE utf8_bin '.$null);
}
Dazu musst du in einer Schleife die Tabellen auslesen und in einer inneren Schleife die Spalten.

Doch irgendwie hab ich das Gefühl, du machst dir die Sache schwerer, als sie ist.
Welches Problem liegt denn der Aufgabenstellung zugrunde, und was willst du damit erreichen ?



 
Zurück
Oben