• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

Datenbank sichern ab einem gewissen Zeilensatz weg

byron1778

Hacker
Hallo Forum,

ich muss die Datenbank in meiner Firma sichern und dann nach einem Abgleich mit der Zweitdatenbank, wieder zurück spielen, dabei sollen aber keine Dubletten entstehen, bzw. vorhandene Dubletten sollen gelöscht werden.
Die Zweitdatenbank ist ein haargenauer Mitschnitt der ersten Datenbank, leider kam es aber zu Fehlern in den Datenbanken, nun soll ein Dump einer Datenbank erstellt werden, aber ab einem gewisse Datum. Dieses Dump soll dann mit der Zweitdatenbank geprüft werden.

Ich habe mir hierzu mysqldump angesehen, jedoch kann ich darin keine Option feststellen, mit der man zum Beispiel ab dem Datum 1.1.2006 bis 4.1.2006 ein Dump erstellen (möglich wäre natürlich auch ein Dump ab der Stelle 10.000.000 bis 15.000.000)kann.

Als Hinweis: Wir verwenden Winmysql!

Weiss jemand vielleicht, wie ich ein Dump ab einer gewissen Stelle vornehmen kann und dann Dubletten löschen kann? (Die Datenbank hat insgesamt nämlich über 25.000.000 Einträge, und da wird ein gesamtes Dump und dann ein Abgleich mit der anderen Datenbank eine halbe Ewigkeit dauern).

Danke für jede Hilfe schon einmal.

Mfg
Byron
 

Morlon

Member
Sofern in den Daten selber keine timestamps eingepflegt wurden bezweifel ich, dass das geht, denn eine Datenbank speichert nicht für jeden Eintrag noch extra nen timestamp.

Für solche Fälle braucht man halt regelmässige Sicherungen und halt Zeitschlüssel, über die jeder Eintrag einer Zeit zugeordnet werden kann.

Ein kompletter Dump dürfte aber an deiner Stelle auch nicht solange dauern.

Wenn eure DB ordentlich aufgebaut ist, und es dürfen keine Dubletten auftauchen, dann habt ihr doch bestimmt Unique PKs und da kann man die Daten einfach reinlaufen lassen, die Dubletten tauchen dann nur im log als Fehler auf.

MfG
 
OP
B

byron1778

Hacker
Hallo,

danke einmal für die Hilfe.

Wie die Firma die Spezifikationen festgelegt hat für die Datenbank weiss ich leider nicht genau. (Alles ein wenig komisch :))

Ich habe mir folgendes überlegt.

Ich mache eine Abfrage ca so: select datum from dbase where datum between 1.1.2006 and 4.1.2006;

Das Ergebnis, welches ich zurückbekomme schreibe ich dann in eine andere Datenbank.

So sieht mein PHP - Script aus, worin allerdings ein kleiner Fehler liegt, den ich nicht finden kann.

Code:
 <html>
<body>
<p>Hallo</p>
<?php

$database = "dbase";
$user = "root";
$pass = "";
$link = @mysql_connect ("localhost", $user, $pass);

if (! $link) {
die ("Cannot connect to Database: ".mysql_error());
}

@mysql_select_db($database) or die("Cannot open Database: ".mysql_error());

$sql = 'select id from dbase';

$result=mysql_query($sql);
if(mysql_num_rows($result)>0){
$rows=mysql_fetch_row($result);
foreach($rows as $field){print "<p>$field</p>";}}

$database = "anderedbase";
$user = "root";
$pass = "";
$link = @mysql_connect ("localhost", $user, $pass);

if (! $link) {

die ("Cannot connect to Database: ".mysql_error());

}

@mysql_select_db($database) or die("Cannot open Database: ".mysql_error());


$sql = "insert into anderedbase (test) values('$field')";

mysql_query($sql);

?>
</body>
</html>

Das Problem ist jenes, das er nicht die Datensätze aus der Spalte Id in die neue Datenbank schreibt sondern immer nur die Zahl 1.

Kann es sein, dass ich einen falschen Befehl verwende oder wird es nie funktionieren?

Mfg
Byron
 
OP
B

byron1778

Hacker
Ich antworte mir selber.

Habe die Lösung gefunden, jetzt würde ich nur noch gerne wissen, mit welchem Befehl man Dubletten löschen kann?

Code:
<html>
<body>

<?php

$database = "dbase";
$user = "root";
$pass = "";
$linker = @mysql_connect ("localhost", $user, $pass);

if (! $linker) {

die ("Cannot connect to Database: ".mysql_error());

}

@mysql_select_db($database) or die("Cannot open Database: ".mysql_error());

$sql = 'select id from dbase where id between 5 and 1000';

$result = mysql_query($sql);
while($a_row = mysql_fetch_row($result)){
foreach($a_row as $field){

$database = "anderedbase";
$user = "root";
$pass = "";
$link = @mysql_connect ("localhost", $user, $pass);

if (! $link) {

die ("Cannot connect to Database: ".mysql_error());

}

@mysql_select_db($database) or die("Cannot open Database: ".mysql_error());

$sql = "insert into anderedbase (test) values('$field')";

mysql_query($sql);

mysql_close($link);

print "<p>$field</p>";}}

mysql_close($linker);

?>
</body>
</html>
 

Morlon

Member
Ok, zum ersten: das mit dem Datum hab ich gemeint, du könntest also jetzt mit dem befehl "mysql_dump --where"datum between 1.1.2000 and 31.12.2005" ein Dump erstellen (k.A. ob der das mit dem between so nimmt) oder halt per

Code:
SELECT * INTO OUTFILE 'file_name' FROM dbase WHERE datum BETWEEN xx.xx.xxxx AND yy.yy.yyyy;

in eine Datei liest, wobei es sein kann, dass du das * durch die Spaltennamen der Tabelle ersetzen musst - kenn mich mit MySQL nicht so aus - wegen der WHERE-Klausel.

Mit

Code:
LOAD DATA INFILE 'file_name' REPLACE INTO TABLE dbase;

liest du es dann in die andere DB wieder ein, wobei falls z.B: das Attribut id bei euch ein Primary oder Unique Key ist, wird mit REPLACE ein bereits mit der id vorhandenen Datensatz durch den neuen Datensatz aus der ersten DB ersetzt.
Mit IGNORE statt REPLACE wird der neue Datensatz ignoriert und wenn ihr keinen PK oder UK habt, dann wird ein doppelter Datensatz geschrieben, den du dann wieder löschen müsstest.

------

Zu deinem Code:

Wird da nicht nur die ID ausgelesen anstatt der komplette Datensatz zu einer id?

ansonsten, lieber

Code:
<html> 
<body> 

<?php 

$database = "dbase"; 
$database2 = "anderedbase"; 
$user = "root"; 
$pass = ""; 
$linker = @mysql_connect ("localhost", $user, $pass); 

if (! $linker) { 

die ("Cannot connect to Database: ".mysql_error()); 

} 

@mysql_select_db($database) or die("Cannot open Database: ".mysql_error()); 

$sql = 'select * from dbase where id between 5 and 1000'; 

$result = mysql_query($sql); 

while($a_row = mysql_fetch_row($result)){ 

  $sql = "insert into anderedbase (test) values('"; 

  foreach($a_row as $field){ 

    $sql = $sql & " $a_row,";

  }
  
  $sql = $sql & "')";
    print "<p>$sql</p>";
  @mysql_select_db($database2) or die("Cannot open Database: ".mysql_error()); 
  mysql_query($sql); 

} 

mysql_close($linker); 

?> 
</body> 
</html>

einfach mal testen, k.A. obs so funzt hab lange nichts mehr in PHP gemacht und auch nicht mit 2 DB'S gleichzeitig.

edit:
Da du nach Dubletten fragst, habt ihr vermtl keinen Primary oder Unique Key angelegt.

Entweder du schaust, ob MySQL "WHERE NOT EXIST id" beherrscht, oder der einfachste Weg ist, einfach eine 2. Tabelle als Kopie der dbase mittels phpmyadmin zu erstellen.
Die dann leeren, das Attribut id als Primary Key anlegen und dann mittels

Code:
INSERT IGNORE INTO dbasekopie SELECT * FROM dbase;

in die neue Tabelle reinlaufen lassen.

MfG
 
OP
B

byron1778

Hacker
Hallo,

doch wir haben einen Primary Key gesetzt auf ID.
Anhand des Datums wollen wir rausfinden (in einem bestimmten Zeitraum), ob in die andere Datenbank (sie sollten beide dasselbe aufzeichnen - Telefonate, unabhängig voneinander) dasselbe geschrieben wurde.

Deswegen wollen wir in einem bestimmten Zeitraum Daten rausfiltern .

Sollten Datensätze irgendwie mehrmals vorkommen, dann sollen die gelöscht werden.

Wir verwenden WinMysql ohne PHPadmin.

So sieht die Tabelle aus.

Code:
+
| Field      | Type                  | Null | Key | Default             | Extra
|
+------------+-----------------------+------+-----+---------------------+-------
+
| modify     | timestamp             | YES  |     | CURRENT_TIMESTAMP   |
|
| id         | varchar(16)           |      | PRI |                     |
|
| server     | tinyint(2) unsigned   |      | MUL | 0                   |
|
| timestamp  | timestamp             | YES  |     | 0000-00-00 00:00:00 |
|
| call_time  | int(10) unsigned      |      | MUL | 0                   |
|
| caller     | varchar(32)           |      |     |                     |
|
| caller_ti  | tinyint(3) unsigned   |      |     | 0                   |
|
| called     | varchar(32)           |      |     |                     |
|
| called_ti  | tinyint(3) unsigned   |      |     | 0                   |
|
| connected  | varchar(32)           |      |     |                     |
|
| connect_ti | tinyint(3) unsigned   |      |     | 0                   |
|
| diverted   | varchar(32)           |      |     |                     |
|
| divert_ti  | tinyint(3) unsigned   |      |     | 0                   |
|
| incoming   | tinyint(1) unsigned   |      |     | 0                   |
|
| status     | tinyint(1) unsigned   |      |     | 0                   |
|
| length     | mediumint(6) unsigned |      | MUL | 0                   |
|
| linenbr    | tinyint(3) unsigned   |      | MUL | 0                   |
|
| cnxtype    | varchar(16)           |      |     |                     |
|
| servername | varchar(32)           |      |     |                     |
|
| drive      | char(2)               |      |     |                     |
|
| dir        | varchar(80)           |      |     |                     |
|
| file       | varchar(80)           |      |     |                     |
|
| crc        | varchar(8)            |      |     |                     |
|
| arch_time  | timestamp             | YES  |     | 0000-00-00 00:00:00 |
|
| archive    | varchar(32)           |      |     |                     |
|
| arch_type  | tinyint(1) unsigned   |      |     | 0                   |
|
| arch_time2 | timestamp             | YES  |     | 0000-00-00 00:00:00 |
|
| archive2   | varchar(32)           |      |     |                     |
|
| arch_type2 | tinyint(1) unsigned   |      |     | 0                   |
|
| replflag   | tinyint(1) unsigned   |      |     | 0                   |
|
| locking    | tinyint(1) unsigned   |      |     | 0                   |
|
+------------+-----------------------+------+-----+---------------------+-------
 

Morlon

Member
Versuche es mal mit:

Code:
DELETE FROM dbase WHERE id NOT IN (SELECT MIN(a.id) FROM dbase As a GROUP BY a.attribut1, a.attribut2, a.attribut3)

hierbei müssen bei GROUP BY alle Attribute eingetragen werden, die einen Datensatz eindeutig definieren und woran du erkennst, dass dieser doppelt vorkommt, z.B. caller, timestamp, call_time ... denk mal das weisst du besser :) .

Zum Testen erstmal das DELETE durch SELECT * ersetzen.

Die Idee dahinter ist, immer die kleinste id bei doppelten Datensätzen zu behalten und die anderen zu löschen.

MfG
 
Oben