Was ist der beste Weg, um eine viele-zu-viele-Beziehung zwischen Datensätzen in einer einzigen SQL-Tabelle darstellen?

StackOverflow https://stackoverflow.com/questions/474119

Frage

Ich habe eine SQL-Tabelle wie folgt:

Update:. Ich bin die Beispieltabelle als die bestehenden hierarchische Natur der ursprünglichen Daten zu ändern (Staat, Städte, Schulen) ist überschattend die Tatsache, dass eine einfache Beziehung zwischen den Elementen benötigt wird,

entities
id      name               
1       Apple     
2       Orange            
3       Banana             
4       Carrot                
5       Mushroom        

Ich möchte Zweiweg-Beziehungen zwischen diesen Entitäten definieren, so dass ein Benutzer eine Einheit sehen eine Liste aller verbundenen Unternehmen sehen können.

Die Beziehungen durch einen Endbenutzer definiert sind.

Was ist der beste Weg, um diese Beziehungen in der Datenbank zu repräsentieren und anschließend abfragen und aktualisieren Sie sie?

Ein Weg, wie ich es sehe ...

Mein Instinkt sagt eine Beziehungstabelle wie folgt:

entity_entity
entity_id_a       entity_id_b
1                 2
5                 1
4                 1
5                 4
1                 3

Wenn das der Fall, ein geliefertes ENTITY_ID von 4 gegeben, wie würde man alle verknüpften Datensätze erhalten, die 1 wäre und 5?

Ebenso ist eine Abfrage von ENTITY_ID = 1 sollte 2 zurückkehren, 3, 4 und 5.

Vielen Dank für Ihre Zeit und lassen Sie mich wissen, ob ich überhaupt die Frage klären kann.

War es hilfreich?

Lösung

Definieren

eine Einschränkung:. entity_id_a < entity_id_b

Erstellen von Indizes:

CREATE UNIQUE INDEX ix_a_b ON entity_entity(entity_id_a, entity_id_b);
CREATE INDEX ix_b ON entity_entity(entity_id_b);

Zweiter Index muss nicht enthalten entity_id_a, wie Sie es nur verwenden, werden alle a die innerhalb eines b auszuwählen. RANGE SCAN auf ix_b wird schneller sein als ein SKIP SCAN auf ix_a_b.

Füllen Sie die Tabelle mit Ihren Einheiten wie folgt:

INSERT
INTO entity_entity (entity_id_a, entity_id_b)
VALUES (LEAST(@id1, @id2), GREATEST(@id1, @id2))

Dann wählen Sie:

SELECT entity_id_b
FROM entity_entity
WHERE entity_id_a = @id
UNION ALL
SELECT entity_id_a
FROM entity_entity
WHERE entity_id_b = @id

UNION ALL hier können Sie über Indizes verwenden und zusätzliche Sortier für Eindeutigkeit vermeiden.

Alle oben gilt für eine symmetrische und anti-reflexive Beziehung. Das bedeutet, dass:

  • Wenn a ist im Zusammenhang mit b , dann b ist im Zusammenhang mit a

  • a ist nie im Zusammenhang mit a

Andere Tipps

Ich denke, die Struktur, die Sie vorgeschlagen haben, ist in Ordnung.

Um die damit verbundenen Aufzeichnungen etwas tun, wie zu bekommen

SELECT related.* FROM entities AS search 
LEFT JOIN entity_entity map ON map.entity_id_a = search.id
LEFT JOIN entities AS related ON map.entity_id_b = related.id
WHERE search.name = 'Search term'

Ich hoffe, das hilft.

Die Verknüpfungstabelle Ansatz scheint in Ordnung, mit der Ausnahme, dass Sie einen ‚Beziehungstyp‘ möchten, so dass Sie wissen, warum sie verwandt sind.

Zum Beispiel ist die Beziehung zwischen Raleigh und North Carolina nicht das gleiche wie eine Beziehung zwischen Raleigh und Durham. Darüber hinaus sollten Sie wissen, wer das ist ‚Eltern‘ in der Beziehung, falls Sie bedingte Drop-downs fuhren. (D Sie einen Staat auswählen, erhalten Sie die Städte, um zu sehen, die in dem Zustand sind).

In Abhängigkeit von der Komplexität der Anforderungen, die einfache Einrichtung, die Sie jetzt haben möglicherweise nicht ausreichend sein. Wenn Sie einfach nur zeigen müssen, dass zwei Datensätze in irgendeiner Weise verbunden sind, sollte die Verknüpfungstabelle ausreichend sein.

Ich gab schon einen Weg, es in Ihrem Design zu tun, aber ich wollte auch diesen separaten Design Einblick bieten, wenn Sie eine gewisse Flexibilität in Ihrem Design haben und diese näher zu Ihren Ansprüchen passt.

Wenn die Elemente in (nicht überlappende) Äquivalenzklassen sind, möchten Sie vielleicht Äquivalenzklassen die Basis für den Tabellenentwurf machen, wo alles in der Klasse wird als gleichwertig betrachtet. Die Klassen selbst kann anonym sein:

CREATE TABLE equivalence_class (
    class_id int -- surrogate, IDENTITY, autonumber, etc.
    ,entity_id int
)

entity_id sollte für eine nicht-überlappende Partition des Raumes eindeutig sein.

Dies vermeidet das Problem der richtigen Links- oder Rechtshänder-ness zu gewährleisten oder eine obere rechte Beziehung Matrix zwingt.

Dann ist Ihre Abfrage ist ein wenig anders:

SELECT c2.entity_id
FROM equivalence_class c1
INNER JOIN equivalence_class c2
    ON c1.entity_id = @entity_id
    AND c1.class_id = c2.class_id
    AND c2.entity_id <> @entity_id

oder äquivalent:

SELECT c2.entity_id
FROM equivalence_class c1
INNER JOIN equivalence_class c2
    ON c1.entity_id = @entity_id
    AND c1.class_id = c2.class_id
    AND c2.entity_id <> c1.entity_id

Ich kann von ein paar Möglichkeiten denken.

Ein einziger Pass mit einem CASE:

SELECT DISTINCT
    CASE
        WHEN entity_id_a <> @entity_id THEN entity_id_a
        WHEN entity_id_b <> @entity_id THEN entity_id_b
    END AS equivalent_entity
FROM entity_entity
WHERE entity_id_a = @entity_id OR entity_id_b = @entity_id

oder zwei gefilterten Abfragen unioned so:

SELECT entity_id_b AS equivalent_entity
FROM entity_entity
WHERE entity_id_a = @entity_id
UNION
SELECT entity_id_a AS equivalent_entity
FROM entity_entity
WHERE entity_id_b = @entity_id
select * from entities
where entity_id in 
(
    select entity_id_b 
    from entity_entity 
    where entity_id_a = @lookup_value
)

Auf der Basis Ihres aktualisierten Schema soll diese Abfrage umgehen:

select if(entity_id_a=:entity_id,entity_id_b,entity_id_a) as related_entity_id where :entity_id in (entity_id_a, entity_id_b)

Dabei gilt: ENTITY_ID wird an das Unternehmen gebunden Sie abfragen

Mein Rat ist, dass Ihr intial Tabellenentwurf ist schlecht. Bewahren Sie keine unterschiedlichen Arten von Dingen in der gleichen Tabelle. (Erste Regel von Datenbank-Design, bis es mit lagere nicht mehr Informationen auf das gleiche Gebiet). Das ist viel schwieriger zu Abfrage und erhebliche Performance-Probleme auf dem Weg führen. Außerdem wäre es ein Problem, die Daten in die realtionship Tabelle eintragen - wie Sie wissen, welche Einheiten müssten realted werden, wenn Sie einen neuen Eintrag zu tun? Es wäre viel besser, richtig relationale Tabellen zu entwerfen. Entity Tabellen sind fast immer eine schlechte Idee. Ich sehe keinen Grund, überhaupt aus dem Beispiel in einer Tabelle, um diese Art von Informationen zu haben. Ehrlich gesagt würde ich eine Universität Tisch und eine verwandte Adresstabelle. Es wäre einfach zu abfragen und weit besser.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top