bierkistenschlepper
Goto Top

MySQL 5.0 Constraints - Bedingungen

Hallo,

ich finde in der Referenz von MySQL keine Möglichkeit für Constraints. Wir haben das in der Vorlesung (für SQL) mit der Check-Klausel gelernt, aber das scheint nicht zu funktionieren. Ich möchte Bedingungen der Form Wert a ist zwischen 0 und 10 und Wert b ist aus der Menge der Werte {10, 100, 1000} erzeugen. Natürlich auch für Strings.

Und wie erreiche ich, dass beim Anlagen einer Zeile in Tabelle A ein Wert in Tabelle B um eins erhöht wird?

Vielleicht kann mir schnell mal jemand sagen, wie das geht face-smile

Content-Key: 103095

Url: https://administrator.de/contentid/103095

Printed on: April 16, 2024 at 15:04 o'clock

Member: Biber
Biber Dec 02, 2008 at 11:22:15 (UTC)
Goto Top
Moin Bierkistenschlepper,

CHECK CONSTRAINTS sind in der Tat eines der wirklich ärgerlichen Nicht-Features bei mySQL.

Du hast, nach dem gerechtfertigen 10-Minuten-Aufregen über dieses Manko, zwei Umgehungsstrategien:

  • einen Großteil der in der Praxis existierenden CHECK-Problematik lässt sich in mySQL über den bei mySQL gut unterstützten ENUM-Umweg abfackeln. Ein Enum-Wert kann eben nur Werte aus einem geschlossenen Wertebereich annehmen und fast alle Gültigkeiten bei Textfeldern und auch viele der numerischen "Kennzeichen"-Felder bekommst Du damit geregelt. Besser als in den meisten anderen "richtigen" DBMSen.
  • den verbleibenden Bodensatz musst Du "on TransAction" mit Triggern lösen, also einen "BEFORE UPDATE/BEFORE INSERT"-Trigger schreiben, der den Validitätscheck enthält.

Für beides -mySQL und ENUM-Werte wie auch mySQL und Trigger ist die mySQL-Doku- brauchbar.

Grüße
Biber
Member: Bierkistenschlepper
Bierkistenschlepper Dec 02, 2008 at 12:54:47 (UTC)
Goto Top
Hi Biber,

Danke, das habe ich mir fast schon gedacht...

Sehe ich das falsch, oder lassen sich mit Enum keine numerischen Wertebereiche machen? Denn in der Referenz steht etwas on Strings.

Außerdem hast du wohl meine letzte Frage übersehen? Wäre sehr schön, das zu erfahren face-smile
Member: Biber
Biber Dec 02, 2008 at 13:43:08 (UTC)
Goto Top
Moin Bierkastenschlepper,

Sehe ich das falsch, oder lassen sich mit Enum keine ...
Du siehst das richtig, ENUM-Werte sind Strings (und bestenfalls NULL oder Leerstrings '' )
Das heißt, Du könntest zwar ein Feld SchulNoten definieren:
 SchulNoten ENUM ('1', '2', '3', '4', '5', '6') 
aber die ENUM-Werte sind Ziffern (im Sinne von Buchstaben >="0" <="9".
Zufällig wäre der ENUM-Index, nach dem Du auch suchen oder ihn abfragen kannst, bei der Note "1" auch Index 1, bei "2" auch Index 2 etc.
In diesen Fällen, wenn es mal so schön aufgeht wie in diesem Beispiel, lasse auch mich dann dazu verleiten, dieses Wissen (Note "1" entspricht ENUM-Index 1) auch in der Abfrage zu nutzen.
Obwohl die DB selbst zu keinem Zeitpunkt zugesichert hat, das diese "Übereinstimmung" von der DB immer eingehalten werden wird.

Die zweite Frage habe ich natürlich NICHT überlesen.
Aber ich dachte, wenn ich Dich eh in Richtung Trigger losjage, stolperst Du zwangsläufig über die AFTER INSERT-Trigger.
Und passt den Rest selbst an....
Anders ausgedrückt: Ich überlas es nicht, ich überlies es Dir.

Falls nicht akzeptabel, dann liefere mal das etwas handhabbarere Beispiel mit Tabellen- und Feldnamen der beiden Tabellen.

Grüße
Biber
Member: Bierkistenschlepper
Bierkistenschlepper Dec 03, 2008 at 10:48:57 (UTC)
Goto Top
Ok danke schonmal! Ich habe eine Tabelle users_competitions, in der jeder Benutzer seine Teilnahme an Wettkämpfen eintragen kann. Nun möchte ich, dass in der Tabelle competitions der Wert participants um eins hochgesetzt wird, sobald ein User sich für diesen Wettkampf anmeldet. Nur weiß ich nicht, wie ich dann die WHERE-Klausel schreibe, denn ich bin ja in der Tabelle competitions... In der users_competitions stehen verschiedene Wettbewerbe drin und der Trigger muss also rausfinden bei WELCHEM Wettbewerb er in competitions den WErt participiants hochsetzen soll. Hier mal mein Ansatz:
CREATE TRIGGER participants AFTER INSERT ON users_competitions FOR EACH ROW BEGIN
UPDATE users_competitions SET participiants WHERE

Ich wüßte auch noch gerne, wie ich participiants sperren kann, damit dieser Wert nur noch durch Trigger verändert werden kann. DEr User soll damit ja nichts zu tun bekommen.
Member: Bierkistenschlepper
Bierkistenschlepper Dec 12, 2008 at 11:42:20 (UTC)
Goto Top
Ok, dieses Problem haben wir nun anderweitig beseitigt. Nun allerdings ein neues Problem:

Wie kann ich prüfen, ob zu einem Eintrag in einer zweispaltigen Tabelle ein Eintrag mit vertauschten Werten existiert? z.B.

a b
b a

SELECT userid1, userid2 FROM friends WHERE EXISTS (SELECT userid2, userid1 FROM friends WHERE tja, was soll jetzt hier hin?

Wenn ich die zwei Spalten in der äußeren Anfrage mit AS benenne, so erkennt er diese Namen in der Inneren Anfrage nicht mehr.
Member: Biber
Biber Dec 12, 2008 at 16:06:44 (UTC)
Goto Top
Moin Bierkistenschlepper,

es geht mich ja nichts an, aber ....
Ihr solltet mal eine Applikation/eine GUI drüberlegen über diese Tabellenbefüllung.
Wird denn da gar nichts bei der Eingabe geprüft?
Oder werden die Daten jeden Freitag abend durch eine Güllepumpe reingedrückt?

Ich würde die Abfrage straigth forward so runtertippseln:
SELECT t1.userid1, t2.userid2 
FROM friends t1, friends t2
WHERE t1.userid1 = t2.userid2
And t1.userid2 = t2.userid1
Und falls ihr mehr als 50000 Datensätze drinhabt, dann legt vorher zum PK auf UserID1 und UserId2 noch eben einen Alternate Key auf die umgekehrte Kombination "UseriD2, UserID1" an.

P.S. Sollte das NICHT auf Anhieb klappen mit meinem Freehand-Statement, dann mach bitte einen neuen Beitrag auf.

Grüße
Biber
Member: Bierkistenschlepper
Bierkistenschlepper Dec 12, 2008 at 16:25:00 (UTC)
Goto Top
Nee, das funktioniert nich.

Zum Verständnis: Die Tabelle modelliert Freundschaften. Ist für das Userpärchen a, b nur eine Zeile da, so wurde eine Einladung verschickt. sind zwei Zeilen da (also a, b und b, a) so besteht eine Freundschaft.

Mit deiner Anfrage erhalte ich
userid1 userid2
3 3
2 2

Was ja keinen Sinn ergibt. Ich möchte Für jede Freundschaft eine Zeile haben. Irgendwie muss das doch möglich sein... Vielleicht klappt es nur, wenn man sich auf einen bestimmten User beschränkt und somit alle seine Freundschaften anzeigt?
Member: Biber
Biber Dec 13, 2008 at 12:35:37 (UTC)
Goto Top
Moin Bierkistenschlepper,

sorry, diese Anzeige macht wirklich keinen Sinn .- es sollte als zweites Feld natürlich die UserIdZwo aus TabelleEins anzeigt werden.

Also nochmal:
SELECT t1.userid1, t1.userid2 
FROM friends t1, friends t2
WHERE t1.userid1 = t2.userid2
And t1.userid2 = t2.userid1

Oder, damit es wirklich bio-optisch ersichtlich ist, meinetwegen den bestätigten Spiegelsatz komplett dazu:
SELECT t1.userid1, t1.userid2,
 t2.userid1  as t2Userid1, t2.userid2 as t2Userid2
FROM friends t1, friends t2
WHERE t1.userid1 = t2.userid2
And t1.userid2 = t2.userid1

Jetzt sollten Pärchen rausfallen, die diese Form haben.
3, 2, 2, 3
47, 11, 11, 47

Grüße
Biber
Member: Bierkistenschlepper
Bierkistenschlepper Dec 15, 2008 at 15:45:55 (UTC)
Goto Top
Dafür bekomme ich jetzt 4 Spalten raus...

userid1 userid2 t2Userid1 t2Userid2
3 2 2 3
2 3 3 2

Ist das denn überhaupt möglich was ich machen will oder müssen wir uns eine andere Implementierung überlegen...? Ich kopier dir hier mal unsere Tabelle:
CREATE TABLE IF NOT EXISTS friends (userid1 int(6), userid2 int(6), PRIMARY KEY (userid1, userid2),
FOREIGN KEY (userid1) REFERENCES users(userid), FOREIGN KEY (userid2) REFERENCES users(userid))ENGINE=InnoDB;

Wobei du die Foreign Keys dann halt löschen musst. Und die Beispieldaten:
INSERT INTO friends VALUES (2, 3);
INSERT INTO friends VALUES (3, 2);
INSERT INTO friends VALUES (2, 4);
Member: Biber
Biber Dec 15, 2008 at 16:55:56 (UTC)
Goto Top
Moin Bierkistenschlepper,

gerade komme ich aus der Bremer Innenstadt, wo mich TAUSENDE von Desperate Katenhousewives aus Verden und Delmenhorst mit meterbreiten C&A-Tüten in die Arme ihrer nikolausbemützten und glühweinumwaberten Prollgatten getrieben haben...

Da dacht ich, ich geh mal ein bisschen im Forum chillen und lese deinen Post...

21...
22...
23...
Was willst Du?!?

Vor gefühlten 27 Kommentaren habe ich vergeblich darum gebeten, für dieses MySQL-aber-wirklich-nicht-Constraints-Problem doch bitte einen neuen Beitrag aufzumachen, wenn wir nicht mit einem Schnellschuss fertig werden.

Ich habe bezugnehmend auf Deinen Kommentar 12.12.2008 um 12:42:20 Uhr: versucht, genau diese Anzeige, die bei Dir "a b" vs "b a" heißt nachzubilden.

Und: works as designed.
Von den 4 Spalten sind, wie ich oben geschrieben habe, die letzten beiden nur zur Überprüfeng:
Ja, die müssen nicht sein.

Aber aufgelistet werden alle "Freundschafts"-Kombinationen, die von beiden Seiten (UserId1 und UserId2) bestätigt worden sind.
Genau so hast Du die Persistierung angelegt
  • wenn User A eine Freundschaft mit User B "wünscht", wird ein neuer Satz angelegt
  • wenn User B diese Freundschaft mit User A bestätigt, wird auch ein neuer Datensatz spiegelbildlich angelegt.

Wenn das so keinen Sinn macht (=Designproblem), dann speichere doch bei der Kombination "UserA-UserB" bei Bestätigung nicht einen neuen Datensatz, sondern UPDATE diese Information im vorhandenen Satz in einem Statusfeld "Bestätigt" mit TRUE oder in einem Datumsfeld "BestätigtAm" mit Tagesdatum.
Dann hast Du definitiv keinen Informationsverlust und kannst es sinnvoller handeln.

Anyhow, meine Bitte: wenn auch das wieder nur wenig weiterhilft, mach bitte einen neuen Beitrag auf.

Grüße
Biber
Member: Bierkistenschlepper
Bierkistenschlepper Dec 15, 2008 at 18:14:02 (UTC)
Goto Top
Achso, die dienen nur zur Überprüfung. Das war mir nicht ganz klar! Ja, dann funktioniert es wohl so!

Vielenk Dank nochmal für deine Mühe!

Und der Weihnachtsrummel geht mir auch auf den Senkel! Ich gegebe mich seit Anfang Dezember kaum noch in die Stadt, geschweige denn auf den Weihnachtsmarkt!

Und Wegen dem Beitrag: Für mich ist ein Beitrag ein Kommentar und ein neues Thema heißt bei mir Thread face-smile Daher habe ich das eben doch noch hier rein gepostet. Reines Missverständnis!