mySQL Doppeleinträge verhindern in beziehungstabelle Unique key

Diskordier

Neu angemeldet
Registriert
14 Juli 2013
Beiträge
161
Hallo leute ich hab eine Tabelle mit zwei Feldern darin sind IDs gespeichert

mit Unique key über zwei Tabellen kann ich einstellen das keine doppelten Einträge erstellt werden .

1 3
3 4
1 5
2 3
1 3 <- wird nicht gemacht da doppelt
3 1 <- das wird gemacht , soll aber nicht weil der Bezug symmetrisch ist :buh:

Wie kann ich das verhindern?

Danke für HIlfe.
 
Auch wenn ich dir bei deinem direkten Problem nicht weiterhelfen kann, klingt das erstmal so, als wäre deine Datenbankstruktur nicht ideal aufgebaut. Kannst du deine Situation genauer beschreiben?
 
Dein sollte strukturiert sein, es sollte also eigentlich nicht passieren das du mal einen eintrag in die erste und mal in die 2te spalte schreibst.
Sollte es doch passieren, ist der Aufbau deiner Datenbank nicht wirklich logisch. Abhilfe könntest du schaffen indem du vor dem schreiben der Daten auf den eintrag prüfst.

[src=mysql]
SELECT * FROM table WHERE xx = 3 LIMIT 1
[/src]
erhältst du ein Ergebnis, darf nichts eingetragen werden
 
Hm, würde es nicht schon helfen das man die beiden Zahlen "sortiert" ? - Also das immer der kleine Nenner links und der größere rechts steht in der Abfrage/Eintrag? :)

So wäre immer sichergestellt das immer die gleiche Aufteilung vorhanden ist, sogar ohne auf den Wert erneut zu prüfen. Nein? Und man kann ohne schlechtes Gewissen einen Insert machen der dann nichts mehr bewirkt, weil herausgefiltert/ignoriert.
 
Wie kann ich das verhindern?

Ich bin mir nicht sicher, wie dein Datenbankdesign allgemein aussieht, vielleicht ließe sich das durch Design-Anpassungen vermeiden.
Falls nicht, würde ich hier eher auf die Anwendungsebene wechseln.

Statt die ID's so einzutragen, wie sie rein kommen, sollte deine Anwendung eine "Normalisierung" durchführen.
Simpler Algorithmus:

[src=python]# normalizes
def normalize(ids):
io_ids = ids.copy()
io_ids.sort()
return io_ids


# incoming id's in what ever order
ids_ooo = [3, 2]
ids_io = normalize(ids_ooo)

# work with the ids
print(ids_io)[/src]

Funktionsweise: Du steckst die IDs in beliebiger Reihenfolge rein und bekommst sie "normalisiert" heraus.
Dazu legen wir zunächst eine Kopie der ursprünglichen Liste an. Ob das nötig ist oder du auf der originalen Liste arbeiten kannst, hängt von deinem konkreten Einsatzzweck ab. Die IDs werden in aufsteigender Reihenfolge zurück gegeben.

Grundlegende Idee:
Wenn du zwei IDs normalisierst, (besser gesagt deren Reihenfolge) landet folglich immer die kleinere ID an Position 1 und die größere an Position 2.
Wenn du nun also ganz allgemein zwei Tupel von IDs hast, so dass: (x, y), (y, x)
dann ist die Repräsentation innerhalb der Datenbank für beide Tupel identisch und in der Datenbank würde durch deine Anforderung der Eindeutigkeit kein doppelter Eintrag entstehen..



Nachtrag:
Wenn nicht klar ist, ob deine Anwendung sich stets an die Konvention hält, dann kannst du natürlich auch deine Datenbank diese Anforderung erfüllen lassen:

INSERT:
[src=mysql]VALUES (LEAST(15, 10), GREATEST(10, 15))[/src]

SELECT:
[src=mysql]WHERE `first` = LEAST(2, 1) AND `second` = GREATEST(1, 2)[/src]

Wenn die Queries aus einer Anwendung kommen, kannst du das auch mit Views und Triggern(?!) entsprechend "verstecken".
 
Zuletzt bearbeitet:
@virtus: Eine If Abfrage in PHP ob die ID 1 oder 2 größer ist als 2 oder 1, reichen doch auch schon aus dann Und dann wird nur der Query richtig "eingestellt" bzw. der "korrekte" verwendet. ;)

Zur Not helfen zwei Ternary Vergleiche in einer Zeile, wenn "x < y ? x : y".... nicht unbedingt schön, aber auch richtig, wobei mir noch ein Logikhändling fehlen würde, ob die IDs gleich sind - warum auch immer ;)
 
Zuletzt bearbeitet:
@theSplit:
Welche Programmiersprache er einsetzt, ist letztlich vollkommen egal. Selbstverständlich kann er auch PHP verwenden.

Warum ich im Beispiel hier keine "einfache" if-Abfrage genutzt habe:
(1) Wie die Normalisierung funktioniert (Position 1: kleinerer Wert, Position 2: größerer Wert) ist eine grundsätzliche Design-Entscheidung. Der Hintergedanke ist, dass du dieses Schema an einer Position im Code festlegst und an allen Stellen, an denen du Normalisierung brauchst, keinen Gedanken mehr daran verschwenden musst, wie genau normalisiert wird, sondern nur noch festlegen musst, dass Normalisierung angewendet wird.
Um es anschaulicher auszudrücken: Stell dir vor du hast mehrere Entwickler. Würdest du an jeder Stelle "in place" die Normalisierung definieren, müssten sich alle Entwickler untereinander abstimmen und an wirklich jeder Stelle genau das Normalisierungsschema umsetzen. Das erfordert zum Einen einen höheren Koordinationsaufwand und ist natürlich auch deutlich Fehleranfälliger, sowohl durch Absprachefehler (Person A ordnet aufsteigend, Person B absteigend), als auch durch Implementierungsfehler. Klar, hier handelt es sich "nur" um zwei Zahlen, die geordnet werden sollen. Bei der Normalisierung von Alpha-Nummerischen Zeichenketten kann es schon schwerer werden:
"Hans Peter", "hans peter", "Hans peter", "hansPeter", "hans_peter", "hans-peter" ...

(2) Stell dir vor die IDs werden irgendwann komplexer, so wie ich das mit dem Namen bereits angedeutet habe. Dann willst du nicht an jeder Stelle im Code die Normalisierung anpassen. Selbst dann nicht, wenn du bei der Entwicklung peinlich genau geachtet hast, dass du Suchen-Ersetzen nutzen kannst.

--- [2017-05-25 00:46 CEST] Automatisch zusammengeführter Beitrag ---

Zur Not helfen zwei Ternary Vergleiche in einer Zeile, wenn "x < y ? x : y".... nicht unbedingt schön, aber auch richtig, wobei mir noch ein Logikhändling fehlen würde, ob die IDs gleich sind - warum auch immer ;)

Gleiche IDs müssen nicht unbedingt eine Verletzung der Anwendungslogik sein. Hierbei wäre eine "Neuanordnung" egal:
(x, x) kannst du beliebig "tauschen" und es wird (x, x) rauskommen. ;)
 
Okay, du hast Recht, ich fands unter anderem nur lustig das du den gleichen Gedankengang wie ich genommen hast... ich wollte es auch zuerst "normalisieren" nennen, bin aber davon abgewichen....

Das man durch eine Funktion die eine eindeutiges Ergebnis produziert, Code "wartbarer" macht, ergibt für mich allerdings auch Sinn, sollte es an mehreren Stellen gebraucht werden. Da gebe ich dir Recht. Hab ich so davor auch nicht gesehen - ist aber mehr als Nachvollziehbar.

Spätestens wenn man nach Zuordnung sucht, wird man die Funktion von dir wieder brauchen, um dann alle Bezüge von 1 zu 3,4, 10... zu suchen, zum Beispiel.
 
Okay, du hast Recht, ich fands unter anderem nur lustig das du den gleichen Gedankengang wie ich genommen hast... ich wollte es auch zuerst "normalisieren" nennen, bin aber davon abgewichen....

Ja, vor allem die zeitliche Überschneidung war unserer beiden Beiträge war überraschend.. :D
Ich finde es nicht unbedingt verkehrt hier von Normalisierung zu sprechen. Auch wenn sie in dem Fall sehr trivial ist.
 
Zuletzt bearbeitet:
Ja, weil Normalisierung ja glaube ich den Kerngedanken besitzt, "Daten" in "ein eingängiges Format" zu bringen.... so wie ich das Konzept verstehe, was ja hier erfüllt wäre. :)
 
Ich vermute nicht, dass ein einfaches "kleinere ID in 1, größere in 2" ausreicht. Was ist, wenn man die Wertepaare (5, 20) und (20, 100) hat?

Wir brauchen einfach mehr Informationen.
 
Zurück
Oben