2015-08-31 43 views
6

W szczególności, potrzebuję usunąć niektóre wiersze z tabeli podczas iteracji nad wszystkimi wierszami w tabeli. Czy DBI ma coś podobnego do aktualizowalnego zestawu wyników w Javie? Tak więc, jeśli zrobię coś takiego:Czy można bezpiecznie aktualizować tabelę MySQL podczas iterowania zestawu wyników za pomocą narzędzia Perl DBI?

$query_all = $dbh->prepare("select Id, X, Y, Z from MyTable"); 
$delete = $dbh->prepare("delete from MyTable where Id = ?"); 
$query_all->execute(); 

while (my @res = $query_all->fetchrow_array()){ 
    my ($id, $x, $y, $z) = @res; 
    # fetch the IDs of any other rows that have the same X, Y, Z values 
    foreach (the_duplicate_ids){ 
     $delete->execute($dup_id); # safe ?? 
     # also delete from another table using $dup_id 
    } 
} 

... czy to w porządku?

Po to, aby podać jakiś kontekst, usuwam zduplikowane wiersze, które mają takie same wartości dla kolumn X, Y, Z, i pozostawia się tylko jeden wiersz w każdym przypadku (pierwszy znaleziony). Jeśli to było wszystko, co robiłem, po prostu ustawiłbym unikalny indeks na tych 3 kolumnach, aby wyeliminować duplikaty, ale muszę również usunąć wiersz z innej tabeli dla każdego duplikatu usuniętego z MyTable.

Na koniec napisałem skrypt, aby zidentyfikować i zebrać wszystkie identyfikatory wierszy, które muszę usunąć w tablicy, a następnie powtórzyć tę tablicę, usuwając odpowiednie wiersze z obu tabel. Nadal jednak jestem zainteresowany znalezieniem odpowiedzi na oryginalne pytanie. Jeśli dostanę czas, spróbuję sam na to odpowiedzieć, ale jeśli ktoś już wie, że chciałbym to usłyszeć.

+2

Powinieneś dodać wyzwalacz, który usuwa odpowiedni wiersz w tabeli pomocniczej po usunięciu wiersza z głównej tabeli. Następnie można dodać unikalne ograniczenie – Borodin

+0

To wydaje się dobrym rozwiązaniem, ale w rzeczywistości nie będzie odpowiednie dla mnie. Moje wymagania zmieniły się nieznacznie, ponieważ muszę trzymać się ostatniego duplikatu dodanego do tabeli zamiast pierwszego, i myślę, że jedyne ograniczenie utrzymuje tylko pierwsze. – RTF

Odpowiedz

1

Martwisz się o równoczesny błąd modyfikacji?

Jeśli korzystasz z transakcji, nie będzie to stanowić problemu, o ile zapiszesz zatwierdzenie po zakończeniu iteracji.

Jednak jeśli używasz trybu automatycznego może to być problemem, a więc rozwiązanie byłoby:

pseudokod owski - nie testowano

#Loop through each row and note the records to delete 
my @deathrow =(); 
foreach my $row (@resultset) { 
    push $row->{id}, @deathrow; 
} 

#Now that we're done iterating, do all the deletes in one statement 
$dbh->execute("DELETE WHERE id IN (" . @deathrow . ")"); #something like that 
0

Możliwym rozwiązaniem byłoby coś razem następujący fragment:

my $dbh = DBI->connect("DBI:mysql:database=XXXX;host=localhost", "user", "pass", {'RaiseError' => 1, 'AutoCommit' => 0}); 

my $query_all = $dbh->prepare("select Id, X, Y, Z from MyTable"); 

eval { 
    my $delete = $dbh->prepare("delete from MyTable where Id = ?"); 
    $query_all->execute(); 
    while (my @res = $query_all->fetchrow_array()){ 
     my ($id, $x, $y, $z) = @res; 
     # fetch the IDs of any other rows that have the same X, Y, Z values 
     foreach my $dup_id (@the_duplicate_ids){ 
      $delete->execute($dup_id); # safe ?? 
      # also delete from another table using $dup_id 
     } 
    }  
    $dbh->commit(); 
}; 

if ([email protected]) { 
    print "Transaction rollback: [email protected]"; 
    $dbh->rollback(); 
}