2009-07-27 3 views
0

Angenommen, ich habe eine Tabelle mit einem Primärschlüssel a_id und Fremdschlüssel b_id.Was ist der beste Weg, um sicherzustellen, dass Primärschlüssel und Fremdschlüssel sich niemals schneiden?

Es ist wichtig, dass sich a_id und b_id niemals schneiden, d. H. Es sollte niemals der Fall sein, dass es einen a_id = b_id gibt.

Was wäre der beste Weg, dies zu implementieren? Könnte ich das irgendwie am Datenbankende machen (mySql), oder sollte dies programmgesteuert sichergestellt werden? Wenn ich dies programmatisch sicherstelle, ist es eine schlechte Praxis, eine Nummer für einen Primärschlüssel einzugeben (anstatt die Datenbank automatisch zu inkrementieren)? Ich nehme an, ich würde nur eine Routine erstellen, die den neuesten Primärschlüssel überprüft und ihn einfach inkrementiert (und ich würde auch sicherstellen müssen, dass der Bereich von a_id niemals den Bereich von b_id schneidet). Irgendwelche Vorschläge?

+0

Normalerweise muss ein Fremdschlüssel mit dem entsprechenden Primärschlüssel übereinstimmen. der Schnittpunkt von A und B muss gleich B sein (obwohl in A Einträge ohne einen übereinstimmenden Eintrag in B enthalten sein könnten). Also, was meinen Sie mit Primär- und Fremdschlüsseln, die sich nicht schneiden? Warum? –

Antwort

2

Sie könnten eine weitere Tabelle erstellen, die das Auto-Inkrement-Feld enthält. Beim Einfügen eines Datensatzes würde er in diese "Schlüsseltabelle" eingefügt und dort die referenzierten Werte verwenden. Wenn Sie also zwei global eindeutige Schlüssel in einer Tabelle haben, wäre jeder Einsatz zwei Schlüsseleinfügungen. Diese Lösung würde auch über 2 hinausgehen.

Aber ich muss fragen: Warum?

+0

Grundsätzlich war die Idee, dass jeder Schlüssel eine generische Objekt-ID darstellt, die ich schließlich auf einer Seite anzeigen kann. Ich wollte, dass die Javascript-Identifikatoren die Objekte generisch durch die Objekt-ID identifizieren (was nicht funktionieren würde, wenn sich a_id und b_id schneiden würden). Ich denke, ich könnte das am Frontend einfach neu gestalten, wenn es zu mühsam ist die db Seite – oym

+0

OK, also anstelle der zweiten eindeutigen Spalte, warum nicht eine andere Spalte wie Object_Type? Weiter könnten Sie eine GUID generieren und diese verwenden. – tsilb

+0

Ich denke, die einfachste Lösung ist, mit der "Master-Tabelle" -Ansatz zu gehen und einfach in diese Tabelle vor irgendwelchen anderen Einfügungen einzufügen und ihre automatisch inkrementierte ID auszuleihen. Danke für den Tipp – oym

1

In Oracle könnten Sie dieses Verhalten mithilfe einer sequence implementieren, die verwendet wurde, um IDs für Zeilen in beiden Tabellen zuzuweisen. Jede Tabelle würde einen Trigger auf haben, wo die ID von der nächsten Nummer in der Sequenz gesetzt würde.

1

Sie können den Wert AUTO_INCREMENT so einstellen, dass eine Tabelle nur ungerade Zahlen und die andere nur even aufweist.

Dies ist wahrscheinlich sehr performant, aber es lässt keinen Platz für das Hinzufügen einer dritten Tabelle mit einem weiteren eindeutigen Schlüssel.

Ich bin nicht 100% sicher über MySQL, aber mit Oracle können Sie eine Sequenz definieren, dann verwenden Sie einfach die gleiche Sequenz, um alle Ihre Werte auszuwählen, was wahrscheinlich die beste Option ist (wenn es mit mysql verfügbar ist).

+0

Dies funktioniert nicht, wenn 'b_id' eine Eltern-ID ist und 'a_id' als Obermenge referenziert. – Eric

+0

Vielleicht habe ich die Frage falsch gelesen, aber ich habe nichts gesehen, das sagt, dass er möchte, dass b_id eine Teilmenge von a_id ist. Wenn das der Fall ist, dann hast du Recht. Derselbe Fehler existiert jedoch, wenn sie eine Sequenz verwenden, wie in einigen anderen Antworten vorgeschlagen. –

0

Der einfachste Weg, dies zu erreichen, wäre die Verwendung einer CHECK Einschränkung. Da MySQL MySQL ist, unterstützt es nicht CHECK. Um den gleichen Effekt in MySQL zu erzielen, müssen Sie einen BEFORE INSERT und einen BEFORE UPDATE Trigger erstellen, um sicherzustellen, dass beide Werte gültig sind. Der FK selbst ist dafür verantwortlich, dass die Beziehung gültig ist. Hier ein Beispiel:

CREATE TRIGGER upd_check BEFORE UPDATE ON sometable 
FOR EACH ROW 
BEGIN 
    IF NEW.a_id = NEW.b_id THEN 
     call ERROR_SELFREFERENCING_ID(); 
    END IF; 
END; 

Mehr Informationen über MySQL TRIGGERS sind in der MySQL-Handbuch:

18.3.1: Trigger Syntax

EDIT: MySQL unterstützt derzeit keine RAISE oder SIGNAL in ihren Auslösern, so muss ich zurückgreifen, um eine nicht existente Prozedur ERROR_SELFREFERENCING_ID() aufzurufen, damit es scheitert. Dies führt dazu, dass INSERT oder UPDATE fehlschlägt, wenn a_id = b_id, ziemlich genau so, wenn Sie einen ungültigen b_id setzen würden.

0

Sie könnten s (UUIDs) als eindeutige Schlüssel verwenden.

Ich habe dies bei mehreren Projekten verwendet und es funktioniert gut für die Eindeutigkeit, obwohl es nicht die beste für die Indexleistung ist.

Verwandte Themen