Christian: (mysql+php) doppelte Einträge vermeiden

Guten Morgen,

ich wollt hier mal in die geballte Kompetenz hineinfragen, was die eleganteste Methode ist, um doppelte Einträge bei mysql zu vermeiden.

Wenn ich mitm 'unique'-Typ arbeite, bricht das Script ja mit der Meldung Duplicate entry ab. Es soll jedoch lediglich nichts eingetragen werden.
Da gibts doch bestimmt noch eine bessere Methode, als vor jedem Eintrag jedes Feld abzufragen, ob es dazu schon die einzutragenen Werte gibt?

Gruß
Christian

  1. Hallo Christian!

    Da gibts doch bestimmt noch eine bessere Methode, als vor jedem Eintrag jedes Feld abzufragen, ob es dazu schon die einzutragenen Werte gibt?

    Ich fürchte nein, denn irgendwie muß dies ja geprüft werden.
    Ob Du das selbst mit nem entsprechenden SELECT machst oder einfach mal nen INSERT machst und ggf. den duplicate-Fehler abfängst schenkt sich imho wenig - außer daß Du wohl "flexibler" bist, wenn Du selbst nen SELECT machst und die eingaben "von Hand" vergleichst.
    Falls Du "Schlüsselfelder" hast, die keine auto_increment-Felder sind sollte es an sich auch reichen, die zu prüfen.

    MfG
    Götz

    --
    Losung für Sonntag, 30. Januar 2005
    Wenn ich auch noch so viele meiner Gebote aufschreibe, so werden sie doch geachtet wie eine fremde Lehre. (Hosea 8,12)
    Paulus schreibt: Treu ist er, der euch ruft; er wird's auch tun. (1. Thessalonicher 5,24)
    (Losungslink)
    1. Hello,

      Ob Du das selbst mit nem entsprechenden SELECT machst oder einfach mal nen INSERT machst und ggf. den duplicate-Fehler abfängst schenkt sich imho wenig - außer daß Du wohl "flexibler" bist, wenn Du selbst nen SELECT machst und die eingaben "von Hand" vergleichst.

      Das ist ein himmelweiter Unterschied im Zeitverhalten (konkurrierender Betrieb)!

      Wenn man das Prüfen und Einfügen nicht in einem atomistischen Statement erledigt, sondern in zwei Statements, dann muss man die mittels geeingeter Lockingstrategie auch binden. Anderenfalls könnte zwischen der Prüfung und den eigenen Insert ein andere Prozess dazwischenschlüßfen mit seinem Insert, und die Prüfung war dann für die Katze... (oder fürn A....)

      So werden dann aus eigentlich einem Insert plötzlich vier Statements:

      Lock
        Select
        Insert
        Unlock

      Harzliche Grüße aus http://www.annerschbarrich.de

      Tom

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau
  2. Wenn ich mitm 'unique'-Typ arbeite, bricht das Script ja mit der Meldung Duplicate entry ab. Es soll jedoch lediglich nichts eingetragen werden.

    ähm ne dumme frage mal... warum bricht ein script ab wegen eines insert fehlers auf einer datenbank?

    Da gibts doch bestimmt noch eine bessere Methode, als vor jedem Eintrag jedes Feld abzufragen, ob es dazu schon die einzutragenen Werte gibt?

    schon mal was von trigger und constraints gehört? fehler protokollieren und script weiter laufen lassen :-)

    Mfg,
    Jonny

  3. ich wollt hier mal in die geballte Kompetenz hineinfragen, was die eleganteste Methode ist, um doppelte Einträge bei mysql zu vermeiden.

    Wenn ich mitm 'unique'-Typ arbeite, bricht das Script ja mit der Meldung Duplicate entry ab. Es soll jedoch lediglich nichts eingetragen werden.

    Einen unique-Index über die betreffenden Spalten hast du ja schon angelegt. Ein

    INSERT IGNORE ...

    hilft dann weiter (siehe MySQL-Doku zu INSERT). Die affected rows zeigen dir sogar an, wieviel Datensätze geschrieben wurden.

    1. Hello,

      Die affected rows zeigen dir sogar an, wieviel Datensätze geschrieben wurden.

      Leider nicht, welche.

      Solche Einfügeinformationen sollte man daher nicht als Multi-Insert ausführen.

      Harzliche Grüße aus http://www.annerschbarrich.de

      Tom

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau
      1. Die affected rows zeigen dir sogar an, wieviel Datensätze geschrieben wurden.

        Leider nicht, welche.

        Solche Einfügeinformationen sollte man daher nicht als Multi-Insert ausführen.

        Heißt das, dass man, nur weil du gern diese Information (welche Datensätze) hättest, diese Funktionalität nicht verwenden darf, wenn man diese Information nicht braucht?

        Dein Einwand ist zwar berechtigt, jedoch würde ich die Wertung ("leider") demjenigen überlassen, der diese Funktionalität einsetzen will. Hier kommt es immer auf den Einzelfall an, und ohne den zu kennen erlaubt ich mir kein Urteil über denn Sinn oder Unsinn von etwas.

        P.S. Ich will dich nicht zurechtweisen, oder mit dir Streit anfangen. Ich mag einfach nur keine voreiligen Verallgemeinerungen.

        1. Hello,

          Die affected rows zeigen dir sogar an, wieviel Datensätze geschrieben wurden.

          Leider nicht, welche.

          Solche Einfügeinformationen sollte man daher nicht als Multi-Insert ausführen.

          Heißt das, dass man, nur weil du gern diese Information (welche Datensätze) hättest, diese Funktionalität nicht verwenden darf, wenn man diese Information nicht braucht?

          Wenn man die Information, ob der Auftrag erfolgreich war, nicht braucht, wird man auch die Daten nicht brauchen, oder? Dann kann man sich das Insert auch gleich schenken oder ins Device NUL umleiten.

          Harzliche Grüße aus http://www.annerschbarrich.de

          Tom

          --
          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
          Nur selber lernen macht schlau
          1. Hello,

            Die affected rows zeigen dir sogar an, wieviel Datensätze geschrieben wurden.

            Leider nicht, welche.

            Solche Einfügeinformationen sollte man daher nicht als Multi-Insert ausführen.

            Heißt das, dass man, nur weil du gern diese Information (welche Datensätze) hättest, diese Funktionalität nicht verwenden darf, wenn man diese Information nicht braucht?

            Wenn man die Information, ob der Auftrag erfolgreich war, nicht braucht, wird man auch die Daten nicht brauchen, oder? Dann kann man sich das Insert auch gleich schenken oder ins Device NUL umleiten.

            Du verallgemeinerst schon wieder voreilig. Folgendes Beispiel aus der Userverwaltung:

            Es gibt die Berechtigungen A, B, C, D usw. In der Tabelle stehen für einen bestimmten Benutzer die Berechtigung A und C (jeweils als ein Datensatz) drin.
            Ein HTML-Formular bietet die Möglichkeit an, Berechtigungen für den Nutzer zu setzen. Dazu sind alle Berechtigungen als Checkbox oder als multiple Select aufgelistet.
            Wenn der Userverwalter nun alle 3 Berechtigungen wählt, sollen am Ende natürlich alle drei Berechtigungen in der Tabelle erscheinen. Dabei ist es unerheblich, ob von diesen Berechtigungen schon welche eingetragen waren.
            Nun könnte der Einwand kommen, dass man vorher die Berechtigungen abfragt und dann nur noch B anbietet. Das mag für einen zu ändernden User noch möglich sein, ist aber unnötiger Aufwand. Und spätestens wenn du mehrere Benutzer mit unterschiedlichen, bereits gesetzten Berechtigungen hast und denen A, B und C setzen willst, geht das nicht mehr.

            Ja, mann kann auch eine Matrik anbieten mit den Berechtigungen in der Waagerechten und den Usern in der Senkrechten. Da empfinde ich aber als bedienunfreundlich, weil man sich dann einen Wolf ankreuzt...

            1. Hello,

              dann musst du eben anschließend mittels zusätzlichem Select prüfen, ob das vorausgegangene Mehrfach-Insert erfolgreich war. Bei einer automatischen Vorgangsbearbeitung müsste man dann ggf. sogar die Tabelle für den Zeitraum bis zur erledigten Erfolgskontrolle sperren. Das ist teuer.

              Es ging darum, dass ein MultiInsert keine Möglichkeit der direkten Kontrolle bietet, ob davon ein einzelnes erfolgreich war oder misslungen ist.

              Ich denke, dass Du das wohl auch verstanden hast.
              Dass Du zusätzlich andere Fälle diskutieren möchtest, ist Dir doch freigestellt.
              Dafür musst Du aber nicht so ein Theater anfangen.

              Harzliche Grüße aus http://www.annerschbarrich.de

              Tom

              --
              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
              Nur selber lernen macht schlau
              1. dann musst du eben anschließend mittels zusätzlichem Select prüfen, ob das vorausgegangene Mehrfach-Insert erfolgreich war.

                Ich sehe an dieser Stelle keinen Unterschied, ob ich einem richtig angewendeten Einzel-Insert oder einem richtig angewendeten Mehrfach-Insert vertraue, dass es seine Arbeit richtig macht oder nicht. Wenn die Datenbank mir keine Fehler zurückliefert war beides erfolgreich. Ob am Ende das Ergebnis rauskommt, das ich bezweckt habe ist doch nicht zwingend von der Art und Weise abhängig, wie ich zum Ziel gelange. Das muss ich in jedem Fall durch geeignete Test während der Programmerstellung prüfen.

                Wenn ich den Faden mal weiterspinne, dürfte deiner Logik zufolge dann auch niemals etwas à la UPDATE ... WHERE x < 1 erlaubt sein.

                Es ging darum, dass ein MultiInsert keine Möglichkeit der direkten Kontrolle bietet, ob davon ein einzelnes erfolgreich war oder misslungen ist.

                Dem ersten Teil dieser Aussage stimme ich voll und ganz zu. Beim zweiten Teil bin ich immer noch nicht überzeugt davon, dass es in jedem Fall notwendig ist, dies so detailliert prüfen zu müssen.

                Ich denke, dass Du das wohl auch verstanden hast.

                Ja. Ich hoffe aber auch, dass du mein Ablehnen von generellen Verallgemeinerungen verstehst.

                Dass Du zusätzlich andere Fälle diskutieren möchtest, ist Dir doch freigestellt.
                Dafür musst Du aber nicht so ein Theater anfangen.

                Hab ich das? War nicht meine Absicht. Ich vertrete nur gerne meinen Standpunkt, wenn mich nicht jemand davon überzeugt, dass er falsch ist.

                P.S. Bin ja schon ruhig... :-) (Zumindest für heute)

                P.P.S. Kann mal jemand dieses Forum ausschalten? Ich wollte heute eigentlich noch was anderes fertigbekommen... :-)

                1. Hello,

                  Ich sehe an dieser Stelle keinen Unterschied, ob ich einem richtig angewendeten Einzel-Insert oder einem richtig angewendeten Mehrfach-Insert vertraue, dass es seine Arbeit richtig macht oder nicht. Wenn die Datenbank mir keine Fehler zurückliefert war beides erfolgreich.

                  Und wenn nun ein Fehler gemeldet wird, welcher Datensatz war dann davon betroffen?

                  Ob am Ende das Ergebnis rauskommt, das ich bezweckt habe ist doch nicht zwingend von der Art und Weise abhängig, wie ich zum Ziel gelange. Das muss ich in jedem Fall durch geeignete Test während der Programmerstellung prüfen.

                  Die Tests während der Programmerstellung haben doch nichts mit dem dynamischen Datenverhalten und den bei vernünftigen Applikationen zwingend notwendigen Konsistenz- und Integritätsprüfungen zu tun, oder? Wie willst Du denn versäumte Prüfungen später nachholen, wenn der Satz bereits in der Anonymität der Menge verschwunden ist?

                  Harzliche Grüße aus http://www.annerschbarrich.de

                  Tom

                  --
                  Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                  Nur selber lernen macht schlau
                  1. Ich sehe an dieser Stelle keinen Unterschied, ob ich einem richtig angewendeten Einzel-Insert oder einem richtig angewendeten Mehrfach-Insert vertraue, dass es seine Arbeit richtig macht oder nicht. Wenn die Datenbank mir keine Fehler zurückliefert war beides erfolgreich.

                    Und wenn nun ein Fehler gemeldet wird, welcher Datensatz war dann davon betroffen?

                    Wenn ich das richtig sehe, dann halte ich deine Vorgehensweise für bedenklich: Du lässt also die Datenbank überprüfen, ob ein bestimmtes Datum in ein bestimmtes Feld passt? Ist es nicht besser, im Vorfeld zu prüfen, ob die Eingabedaten i.O. sind? Ich hoffe, ich irre mich da (bei der ersten Frage; bei der zweiten hoffentlich nicht). Oder welche Fälle gibt es da noch, dass einzelne Insert nicht funktionieren, die ich nicht schon durch das IGNORE ausgeschlossen habe?

                    Ob am Ende das Ergebnis rauskommt, das ich bezweckt habe ist doch nicht zwingend von der Art und Weise abhängig, wie ich zum Ziel gelange. Das muss ich in jedem Fall durch geeignete Test während der Programmerstellung prüfen.

                    Die Tests während der Programmerstellung haben doch nichts mit dem dynamischen Datenverhalten und den bei vernünftigen Applikationen zwingend notwendigen Konsistenz- und Integritätsprüfungen zu tun, oder? Wie willst Du denn versäumte Prüfungen später nachholen, wenn der Satz bereits in der Anonymität der Menge verschwunden ist?

                    Durch ein Prüfen der Daten, _bevor_ ich die Datenbank damit füttere. Dieses Vorgehen wird zu Recht bei nicht vertrauenswürdigen Daten immer wieder gefordert.

                    1. Hello,

                      Wenn ich das richtig sehe, dann halte ich deine Vorgehensweise für bedenklich: Du lässt also die Datenbank überprüfen, ob ein bestimmtes Datum in ein bestimmtes Feld passt? Ist es nicht besser, im Vorfeld zu prüfen, ob die Eingabedaten i.O. sind? Ich hoffe, ich irre mich da (bei der ersten Frage; bei der zweiten hoffentlich nicht). Oder welche Fälle gibt es da noch, dass einzelne Insert nicht funktionieren, die ich nicht schon durch das IGNORE ausgeschlossen habe?

                      Selbstverständlich ist eine vernünftige Datenbank auch in der Lage eine einfache oder eine strenge Typprüfung vorzunehmen. Hier handelt es sich aber erstens um eine SQL-Schnittstelle und zweitens um MySQL. Die SQL-Schnittstelle kann nur Textdaten verarbeiten und solche, die als Textdaten maskiert sind. Eine Typüberprüfung durch die Datenbank kann also nicht vorgenommen werden, sondern bestenfalls eine Formatkontrolle. MySQL ist nur ein "Rumpfsystem", auch wenn das DBMS schon sehr an Funktionsumfang und Sicherheit gewonnen hat, ist es immer noch kein "vollwertiges" DBMS nach dem Stand der Technik. Für einfache Internet-Dialog-Anwendungen genügt es aber.

                      Nun zur Frage, warum trotz passenden Datenformates Inserts schiefgehen könnten:

                      Im konkurrierenden Betrieb ist es nicht ausgeschlossen, dass einzelne Sätze betroffen sind;
                      Beispiele:

                      • ein anderer User hat den Satz mit den entsprechenden Kriterien bereits eingestellt

                      • ein anderer User hält den Satz gesperrt (natürlich nicht bei Insert...)

                      • die Tabelle ist gesperrt

                      • es hat einen Übertragungsfehler gegeben (oder im Satzformat liegt ein Fehler vor)

                      • ...

                      • (Update) der Satz wurde seit dem letzten Lesen von einem anderen User verändert

                      Es gibt dutzende von Gründen, warum eine Datenbankoperation nicht wunschgemäß oder erwartungsgemäß ausgeführt werden kann. Die Missachtung der Statusmeldung direkt nach der Operation ist das Verwerfliche, dass Du mindestns befriedigend "bedenken" solltest.

                      Außerdem ist eine "Fehlermeldung" nichts schlimmes, sondern gibt einem wertvolle Information über den Stand der Verarbeitung.

                      Warum sollte ich also diese Fähigkeit der Datenbank redundant, umständlich und fehlerträchtig (--> race conditions) emulieren?

                      Harzliche Grüße aus http://www.annerschbarrich.de

                      Tom

                      --
                      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                      Nur selber lernen macht schlau
                      1. Guten Morgen!

                        Nun zur Frage, warum trotz passenden Datenformates Inserts schiefgehen könnten:

                        Im konkurrierenden Betrieb ist es nicht ausgeschlossen, dass einzelne Sätze betroffen sind;
                        Beispiele:

                        • ein anderer User hat den Satz mit den entsprechenden Kriterien bereits eingestellt

                        Deswegen ja ein INSERT IGNORE. Wenn der Datensatz schon drinsteht brauche ich ihn ja nicht noch einmal einzufügen (das ist natürlich vom konrekten Einzelfall abhängig). Ob ich auf die Information, dass der Datensatz bereits enthalten war oder nicht verzichten kann oder nicht, ist hier ja das Kriterium ob ich INSERT IGNORE einsetzen kann oder nicht.

                        • ein anderer User hält den Satz gesperrt (natürlich nicht bei Insert...)

                        eben, das war ja auch nicht meine Fragestellung.

                        • die Tabelle ist gesperrt

                        Dann geht ja gar nichts, nicht nur einer von einem Multi-Insert.

                        • es hat einen Übertragungsfehler gegeben (oder im Satzformat liegt ein Fehler vor)

                        Übertragungsfehler kann man durch geeignete Maßnahmen ausschließen. Das ist kein spezielles Problem bei INSERT IGNORE

                        Es gibt dutzende von Gründen, warum eine Datenbankoperation nicht wunschgemäß oder erwartungsgemäß ausgeführt werden kann. Die Missachtung der Statusmeldung direkt nach der Operation ist das Verwerfliche, dass Du mindestns befriedigend "bedenken" solltest.

                        Das ist mir global gesehen völlig klar, das habe ich auch nicht bestritten. Ich dachte nur, wir reden hier speziell über Multi-Inserts mit INSERT IGNORE.

                        Außerdem ist eine "Fehlermeldung" nichts schlimmes, sondern gibt einem wertvolle Information über den Stand der Verarbeitung.
                        Warum sollte ich also diese Fähigkeit der Datenbank redundant, umständlich und fehlerträchtig (--> race conditions) emulieren?

                        Um solche allgemeinen Sachen geht es mir doch gar nicht...

                        Ich seh schon, ich kann dich nicht davon überzeugen, dass INSERT IGNORE nichts generell Schlechtes ist, sondern dass im jeweiligen Einzelfall seine Eigenschaften betrachtet und entsprechend bewertet werden müssen.

                        P.S. Mein Kollege sagt immer: "Wer Recht hat, gibt einen aus." In dem Sinne, Prost!   c(_)  :-)

    2. hallo,

      INSERT IGNORE ...

      hilft dann weiter (siehe MySQL-Doku zu INSERT).

      ah, danke!