Pit: Betroffene Datensätze / mysqli

Hallo,

ich habe eine Query ala:

DELETE FROM tabelle WHERE ID NOT IN (SELECT ID FROM tabelle2);

Ich würde mir gerne im "Erfolgsfall" die gelöschten IDs mitloggen. Aber wie spucke ich die aus?

$mysqli->affected_rows ist nicht das, was ich suche... ich hätte wirklich die IDs selber gerne geloggt und ich befürchte, dass das mit meiner Query nicht geht. Oder gibts da einen Weg?

Pit

  1. Hallo Pit,

    nein, das geht nicht. Dafür müsstest Du die zu löschenden IDs vorher mit einem SELECT holen.

    Muss es wirklich sein? Jede Lösung, die auch im Multiuser-Betrieb wasserdicht ist, müsste während des Löschvorgangs erstmal Locks setzen und die DB ausbremsen.

    Wenn diese Query ein "Aufräumbatch" ist, der nicht von beliebigen Usern angestoßen werden kann, dann kannst Du es für 99% Sicherheit in zwei Schritten machen.

    SELECT ID FROM tabelle WHERE ID NOT IN (SELECT ID FROM tabelle2);
    

    Diese Ergebnismenge liest Du in dein Programm und protokollierst. Danach rufst Du den DELETE. Falls allerdings zwischen SELECT und DELETE ein Satz aus tabelle2 gelöscht wurde, wird dessen ID aus tabelle1 gelöscht ohne dass protokolliert wurde.

    Um sicherer zu sein, könntest Du die zu löschenden IDs in eine TEMP-Tabelle des Users SELECTen, danach die Temp-Tabelle ins Programm lesen und danach den DELETE so aufsetzen dass er die IDs der TEMP-Tabelle löscht. Das ist aber viel Mühe für ein paar geloggte IDs.

    Aber wenn Sätze in tabelle zu löschen sind, wenn die ID nicht in tabelle2 steht - ist dann die ID in tabelle nicht ein Foreign Key? Den könntest Du per Kaskade automatisch löschen und wüsstest dann ganz genau, dass nach einem DELETE in tabelle2 in tabelle aufgeräumt wurde.

    Rolf

    --
    sumpsi - posui - clusi
    1. Hallo Pit,

      nein, das geht nicht. Dafür müsstest Du die zu löschenden IDs vorher mit einem SELECT holen.

      Hi Rolf,

      ja, das habe ich mir gedacht. Deshalb mache ich es bisher so, wie Du vorschlägst, also über einen zuvorigen select.

      Muss es wirklich sein? Jede Lösung, die auch im Multiuser-Betrieb wasserdicht ist, müsste während des Löschvorgangs erstmal Locks setzen und die DB ausbremsen.

      Nein, das muß grad nur temporär sein, weil ich zu Debuggingzwecken feststellen möchte, an welcher Stelle ungerechtfertigt IDs gelöscht werden. Aber ich glaube, ich habe die Stelle soeben schon gefunden. Ich habe einen "Where-Zusatz" vergessen, der dafür sorgt, dass nicht nur IDs des betroffenen Vorgangs gelöscht werden, sondern alle Vorgänge zu betroffenen Vorgängen macht.

      Meine Query hätte also:

      SELECT ID FROM tabelle WHERE Bedingung = ... AND ID NOT IN (SELECT ID FROM tabelle2 WHERE ...);
      

      Danke für die Hilfe jedenfalls,

      Pit

  2. Tach!

    Ich würde mir gerne im "Erfolgsfall" die gelöschten IDs mitloggen. Aber wie spucke ich die aus?

    DELETE erzeugt keine Ergebnismenge. Und es würde mich wundern, wenn es eine erzeugen würde, die mit einem nachfolgenden Statement abzufragen geht.

    Mal allgemein gesprochen: Nicht alle Tabellen haben Primary Keys, und ob immer nur die IDs von gelöschten Datensätzen interessant sind, ist auch keine Regel. Wie also müsste das DBMS arbeiten? Datensatz löschen, gut. Aber da davon noch Werte interessant sind, kopieren wir vorher die Daten anderswohin. Hmm, zuzüglich der Datensätze bei Cascade Delete? Und dann muss die Menge (oder Teile daraus) zum Client kommen, dann kann auch das weg. Aber lohnt es sich, solch ein Vorgehen einzubauen? Nicht wirklich. Die Datensätze, die vom WHERE betroffen sind, kann man sehr gut auch vorher per SELECT ermitteln. Man kann sich das Umständliche also sparen.

    ich hätte wirklich die IDs selber gerne geloggt und ich befürchte, dass das mit meiner Query nicht geht. Oder gibts da einen Weg?

    Es geht noch andere Wege, besonders wenn die Wahrscheinlichkeit hoch ist, dass zwischen Select und Delete Änderungen in der Menge auftreten könne, und das berücksichtigt werden muss. Wird aber alles umständlicher.

    • Selektiere die IDs der zu löschenden Datensätze, und erzeuge daraus eine Temporary Table (INSERT ... SELECT ...).
    • Lösche die Datensätze, deren IDs in der Temptable sind.
    • Selektiere alle Daten der Temptable mit einem normalen SELECT und Fetchen.
    • Schließe die Verbindung, Temptable wird dabei gelöscht.

    dedlfix.

    1. Hi dedlfix,

      DELETE erzeugt keine Ergebnismenge. Und es würde mich wundern, wenn es eine erzeugen würde, die mit einem nachfolgenden Statement abzufragen geht.

      Die Datensätze, die vom WHERE betroffen sind, kann man sehr gut auch vorher per SELECT ermitteln. Man kann sich das Umständliche also sparen.

      Ja, genau das habe ich auch gemacht.

      Es geht noch andere Wege, besonders wenn die Wahrscheinlichkeit hoch ist, dass zwischen Select und Delete Änderungen in der Menge auftreten könne, und das berücksichtigt werden muss. Wird aber alles umständlicher.

      • Selektiere die IDs der zu löschenden Datensätze, und erzeuge daraus eine Temporary Table (INSERT ... SELECT ...).
      • Lösche die Datensätze, deren IDs in der Temptable sind.
      • Selektiere alle Daten der Temptable mit einem normalen SELECT und Fetchen.
      • Schließe die Verbindung, Temptable wird dabei gelöscht.

      Danke für den Tip. Werde ich so machen, wenn das Problem nochmal auftaucht. In diesem Fall bin ich fündig geworden, was den fehler im Programm anging.

      Pit