Felix Riesterer: DELETE über unbekannt viele Tabellen hinweg...?

Liebe Mitlesende,

aus einer Datenbank (MySQL 5.1.41-community) möchte ich eine Person aus allen Tabellen austragen, die in der Datenbank eine Spalte mit "PersonenID" haben. In meinem Projekt verwende ich (absichtlich) keine foreign keys, sodass die DB nicht von selbst alle PersonenIDs aus ihren Tabellen putzt - und ich möchte das auch genau so haben, damit ich mit meinen Queries während des Entwickelns nicht noch mehr Fehlermeldungen bekomme.

Was ich schon kann:
* einen Datensatz aus einer Tabelle (hier "personen") löschen:

DELETE FROM `personen`  
WHERE `PersonenID`='1234';

* alle Tabellen in Erfahrung bringen, in denen eine Spalte "PersonenID" existiert:

SELECT `TABLE_NAME`  
FROM `information_schema`.`COLUMNS`  
WHERE `TABLE_SCHEMA`='name_meiner_DB'  
    AND `COLUMN_NAME`='PersonenID';

* in der MySQL-Doku über die Syntax von DELETE und im hiesigen Archiv einen passenden Thread nachlesen, dass es eine Schreibweise für "multiple tables" gibt und wie sie aussehen sollte.

Folgende SQL-Query ist das bisherige Ergebnis meiner Bemühungen, die ohne Fehlermeldung vom MySQL-Server akzeptiert wird, aber leider keine tatsächlichen Löschungen vornimmt:

DELETE `benutzer`.*, `buchungen`.*, `dozenten`.*, `personen`.*  
FROM `benutzer`, `buchungen`, `dozenten`, `personen`  
WHERE `personen`.`PersonenID`='2';

Was ich noch nicht verstehe und deshalb auch noch nicht kann:
* Sind die im MySQL-Handbuch angeführten Joins unerlässlich, um das DELETE-Statement überhaupt mit dem erwünschten Effekt durchführen lassen zu können? Und wenn ja, warum muss ich da etwas joinen?

* Wie notiere ich die WHERE-Klausel, wenn ich die exakte Anzahl der betroffenen Tabellen nicht "kenne" (zumindest nicht innerhalb derselben SQL-Query)? In meinem PHP-Script speichere ich mit einer gesonderten Anfrage (siehe zweites SQL-Beispiel oben) die Namen der betroffenen Tabellen in einem Array, um dann den eben genannten DELETE per Script zusammenzusetzen...

* Ist mein Ansinnen überhaupt mittels einer einzigen SQL-Query lösbar, oder muss ich das tatsächlich doch "ausprogrammieren"?

Wer kann mir beim Verstehen weiterhelfen?

Liebe Grüße,

Felix Riesterer.

--
ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  1. Hallo,

    kennt mysql denn die INFORMATION_SCHEMA.COLUMNS View. Dann könntest du auf dieser nach Tabellen suchen, welche PersonenID als Spalte beinhalten und für jede Tabelle ein geeignetes DELETE ... WHERE PersonenID=#wert#; ausgeben bzw. dynamisch ausführen lassen. Wenn mysql selbst keine Möglichkeiten dafür bietet, kannst du ja die Tabellennamen in PHP konsummieren und dort entsprechende Statements zusammenfrickeln.

    damit ich mit meinen Queries während des Entwickelns nicht noch mehr Fehlermeldungen bekomme.

    Sehr schön formuliert.

    Cheers, Frank

    1. moin,

      damit ich mit meinen Queries während des Entwickelns nicht noch mehr Fehlermeldungen bekomme.

      Sehr schön formuliert.

      fragt sich, ob er den die anderen fehlermeldungen haben will, wenn es dann um die produktivdatenbank geht, wo die referentielle integrität zum einsatz kommt ;-)

      Ilja

      1. Lieber Ilja,

        damit ich mit meinen Queries während des Entwickelns nicht noch mehr Fehlermeldungen bekomme.
        fragt sich, ob er den die anderen fehlermeldungen haben will, wenn es dann um die produktivdatenbank geht, wo die referentielle integrität zum einsatz kommt ;-)

        1. Wer sagt, dass im Produktiveinsatz dieses Feature aktiv sein soll?
        2. Warum sollte ich nicht ohne dieses Feature auskommen können?
        3. Was willst Du mir eigentlich sagen?

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
          1. Wer sagt, dass im Produktiveinsatz dieses Feature aktiv sein soll?

          "und ich möchte das auch genau so haben, damit ich mit meinen Queries während des Entwickelns nicht noch mehr Fehlermeldungen bekomme"

          Ilja

  2. Tach auch.

    Was spricht dagegen, die Constraints mit "ON DELETE CASCADE" auszuzeichnen, so dass sich das alles mitlöscht?

    Bis die Tage,
    Matti

  3. Hallo Felix,

    aus einer Datenbank (MySQL 5.1.41-community) möchte ich eine Person aus allen Tabellen austragen, die in der Datenbank eine Spalte mit "PersonenID" haben. In meinem Projekt verwende ich (absichtlich) keine foreign keys, sodass die DB nicht von selbst alle PersonenIDs aus ihren Tabellen putzt - und ich möchte das auch genau so haben, damit ich mit meinen Queries während des Entwickelns nicht noch mehr Fehlermeldungen bekomme.

    Meiner Meinung nach putzt er auch mit foreign keys nicht selbst, sondern meckert nur, wenn er irgendwas nicht löschen kann. Außer man folgt dem Vorschlag von Matti mit ON DELETE CASCADE. (man kann vermutlich darüber streiten, ob man das wirklich möchte oder nicht, ich bin da kein Experte)

    Folgende SQL-Query ist das bisherige Ergebnis meiner Bemühungen, die ohne Fehlermeldung vom MySQL-Server akzeptiert wird, aber leider keine tatsächlichen Löschungen vornimmt:

    DELETE benutzer., buchungen., dozenten., personen.

    FROM benutzer, buchungen, dozenten, personen
    WHERE personen.PersonenID='2';

    Es wundert mich, dass es keine Fehlermeldung gibt, denn es enspricht ja nicht der schreibweise für multible tables (Vielleicht täusche ich mich, konnte diese nicht so schnell durchblicken. Ich vermute das gehören noch joins und Aliase dazu, wie du schon feststelltest ;))  
      
    
    > \* Ist mein Ansinnen überhaupt mittels einer einzigen SQL-Query lösbar, oder muss ich das tatsächlich doch "ausprogrammieren"?  
    
    Ich vermute du musst programmieren oder Fremdschlüssel-Constraints verwenden.  
      
    Es gibt wohl noch eine weitere Lösung (sinnvoll oder nicht vermag ich nicht zu bewerten ;))  
      
    ~~~sql
      
    DELETE FROM `table1`,`table2`,`table3` USING `table1`  
    LEFT JOIN `table2` ON `table2`.`id` = 100  AND any_other_condition_for_table2  
    LEFT JOIN `table3` ON `table3`.`id` = 100 AND any_other_condition_for_table3  
    WHERE `table1`.`id` = 100  
    
    

    Dazu musst du in das Statement alle deine Tabellen aufzählen, sollte das Kriterium nicht vorhanden sein, dann hilft der left join beim überlesen.
    Das ist ungetestet, weil ich gerade keine DB zur Hand habe.

    Viele Grüße
    romy

  4. Hallo Ingrid, liebe Antwortende,

    da ich das Feature mit den "foreign key constraints" und dem "on_delete_cascade" erst noch studieren muss (war mir so noch nicht geläufig), werde ich das Problem erst einmal auf der Ebene meines Scripts lösen. Daher iteriere ich momentan durch die ermittelten Tabellen, um in einer jeden mein DELETE durchzuführen.

    Vielleicht bin ich eines Tages in meinen DB-Kenntnissen und -Fertigkeiten etwas weiter, um dann das Problem eleganter zu lösen.

    Das Thema ist für den Moment zwar gegessen, den Thread werde ich aber weiterhin beobachten, denn es könnten sich ja weitere interessante Aspekte ergeben.

    Vielen Dank für die bisherigen Antworten: Danke romy, danke Matti Maekitalo, danke Frank.

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  5. Moin!

    Folgende SQL-Query ist das bisherige Ergebnis meiner Bemühungen, die ohne Fehlermeldung vom MySQL-Server akzeptiert wird, aber leider keine tatsächlichen Löschungen vornimmt:

    DELETE benutzer., buchungen., dozenten., personen.

    FROM benutzer, buchungen, dozenten, personen
    WHERE personen.PersonenID='2';

      
    "For the multiple-table syntax, DELETE deletes from each tbl\_name the rows that satisfy the conditions."  
      
    Deine Bedingung: personen.PersonenID = 2.  
      
    Für welche Zeilen in den Tabellen != "personen" trifft das zu?  
      
    Abgesehen davon: Multi-Tabellen-Delete ist offenbar anspruchsvoller. Warum gehst du direkt in die "vollen" mit der Maximalzahl an Tabellen, anstatt erstmal den einfachsten Multi-Case zu testen mit ZWEI?  
      
    
    > \* Wie notiere ich die WHERE-Klausel, wenn ich die exakte Anzahl der betroffenen Tabellen nicht "kenne" (zumindest nicht innerhalb derselben SQL-Query)? In meinem PHP-Script speichere ich mit einer gesonderten Anfrage (siehe zweites SQL-Beispiel oben) die Namen der betroffenen Tabellen in einem Array, um dann den eben genannten DELETE per Script zusammenzusetzen...  
      
    Das ist so. Alles, was du per Query abfragen kannst, sind Daten. Tabellennamen sind keine Daten. Es gibt keine Möglichkeit, aus Daten direkt im Query Tabellennamen zu machen, das muss eine abfragende Instanz schon selbst regeln.  
      
    
    > \* Ist mein Ansinnen überhaupt mittels einer einzigen SQL-Query lösbar, oder muss ich das tatsächlich doch "ausprogrammieren"?  
      
    Ausprogrammieren. Und insofern ist der Ansatz mit Single-Table-Delete nicht schlechter, als ein Multi-Table-Delete.  
      
     - Sven Rautenberg
    
    1. Lieber Sven,

      ganz herzlichen Dank für Deine konzeptionelle Kritik:

      Alles, was du per Query abfragen kannst, sind Daten. Tabellennamen sind keine Daten. Es gibt keine Möglichkeit, aus Daten direkt im Query Tabellennamen zu machen, das muss eine abfragende Instanz schon selbst regeln.

      Damit ist Dein Fazit eine Bestätigung für mich, dass meine Lösung letzten Endes die sinnvollste ist:

      Ausprogrammieren. Und insofern ist der Ansatz mit Single-Table-Delete nicht schlechter, als ein Multi-Table-Delete.

      Du hast mir in konzeptioneller Hinsicht sehr geholfen, denn nun sehe ich manche Details aus einer etwas anderen Sicht, was mich bei Folgefragen zur Selbsthilfe befähigt.

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)