Doppelte(mehrfache) Werte löschen


tklustig

Erfahrenes Mitglied
Hallo Leute, folgender Codeauszug soll eigentlich alle doppelten bzw, mehrfach vorhanden Records aus der Datenbank entfernen. Die dritte Normalform soll gewart bleiben! Dummerweise entfernt er nicht nur die doppelten Records, sondern beide Dateien. Zumindest eine sollte jedoch in der Datenbank verbleiben. sowohl die unset-Anweisungen als auch das Rücksetzten des counters bewirken nix. Weiß jemand Rat?
PHP:
        foreach ($Files as $file) {
            array_push($filenames, $file->dateiname);
        }
        $Info = array_count_values($filenames);
        foreach ($Info as $value => $counter) {
            if ($counter > 1) {
                unset($Info[$value]);
                $connection->createCommand()
                        ->delete('dateianhang', ['dateiname' => $value])
                        ->execute();
                unset($filenames[$value]);
                array_push($showdeletefiles, $value);
                $counter = 0;
            }
        }
EDIT:
folgendes Query wurde ausgeführt
SQL:
DELETE FROM `dateianhang` WHERE `dateiname`='817_1467699625908067936_Punk4.jpg.jpg'
Das heist, mein Code ist soweit korrekt. Allerdings darf ich nicht nach dem Dateinamen suchen, sondern muss mir den PK greifen, damit mindestens eine Datei in der Datenbank verbleibt. Was denkt Ihr?
 
Zuletzt bearbeitet:

tklustig

Erfahrenes Mitglied
So. Geschafft!;)
Folgender Code verhält sich, wie erwünscht. Ich poste ihn hier komplett, vielleicht hilft er dem einen oder anderen mit denselbem Problem
PHP:
$filenames = array();
        $IdOfFiles = array();
        $connection = \Yii::$app->db;
        $Fk = EDateianhang::findOne(['id_mail_eingang' => $id])->id;
        $Files = Dateianhang::find()->where(['id_e_dateianhang' => $Fk])->all();
        foreach ($Files as $file) {
            array_push($filenames, $file->dateiname);
        }
        $Info = array_count_values($filenames);
        foreach ($Info as $value => $counter) {
            if ($counter > 1) {
                $Re_Files = Dateianhang::find()->where(['dateiname' => $value])->all();
                foreach ($Re_Files as $file) {
                    array_push($IdOfFiles, $file->id);
                }
            }
        }
        for ($i = 0; $i < count($IdOfFiles); $i++) {
            if ($i % 2 == 0)
                $connection->createCommand()
                        ->delete('dateianhang', ['id' => $IdOfFiles[$i]])
                        ->execute();
        }
 

ComFreek

Mod | @comfreek
Moderator
Ich würde das ganze in eine Transaktion einbetten, so geht das leider sehr kaputt bei nebenläufigen Überschneidungen.
 

tklustig

Erfahrenes Mitglied
Sicher läuft die Applikation später unter einem MutliUser-System. Aber was soll denn daran kaputt gehen? Jeder User unserer Applikation bekommt eine eigene Datenbank (in Form eines PHP-Scriptes) zur Verfügung gestellt, soll heißen: Die Applikation läuft auf unserem (Web-)Server, bedient sich allerdings der Daten auf einer lokalen Datenbank. Nur deren Zugangsdaten befinden sich in unserer Datenbank. Inwiefern müsste ich jetzt Transaktionen verwenden? Die Frage ist nicht wie, sondern warum?!
 

ComFreek

Mod | @comfreek
Moderator
Die obige Operation aus Post #2 wird bei ein und demselben Nutzer mehrmals angestoßen. Das kann passieren, wenn etwa obiges Skript durch eine URL "/blub.php" aufgerufen wird. Dann muss "/blub.php" nur zwei Mal fast zur selben Zeit aufgerufen werden, sodass ein und dasselbe PHP-Skript überlappt ausgeführt wird.
Und damit kann es zu Inkonsistenzen führen, was das jeweilige Skript an Datenbestand in der (nutzerlokalen) DB sieht und schreibt.
 

tklustig

Erfahrenes Mitglied
Von ein und denselbem Nutzer kann das Script nicht mehrmals angestoßen werden, wohl aber von anderen Nutzern, die dieselbe Applikation benutzen. Aus diesem Grunde habe die Datenbankoperation in eine Transaktion gepackt.
Im Falle einer Exception wird ein Rollback durchgeführt ,andernfalls ein Commit. Danke für den Hinweis.