Lösung zum Suchen nach "doppelten" Datensätzen mit STI und Eltern-Kind-Beziehung

9

Ich habe ein STI-basiertes Modell namens Buyable, mit zwei Modellen Basket und Item. Die Attribute, die hier für Buyable von Bedeutung sind, sind:

  • shop_week_id
  • Standort-ID
  • parent_id

Es gibt eine Eltern-Kind-Beziehung zwischen Korb und Gegenstand. parent_id ist immer Null für den Warenkorb, aber ein Artikel kann zu einem Warenkorb gehören, indem er auf die eindeutige Warenkorb-ID verweist. Der Korb hat also viele Gegenstände und ein Gegenstand gehört zu einem Korb.

Ich brauche eine Methode für das Basket-Modell:

Gibt true von false zurück, wenn in der Tabelle andere Körbe mit der gleichen Anzahl und Typen von Elementen vorhanden sind. Elemente werden als identisch angesehen, wenn sie die gleiche Shop_Week_ID und Location_ID teilen.

Zum Beispiel:

Gegeben ein Korb (uid = 7) mit 2 Gegenständen:

Punkt # 1

  • id = 3
  • shop_week_id = 13
  • location_id = 103
  • parent_id = 7

Punkt # 2

  • id = 4
  • shop_week_id = 13
  • location_id = 204
  • parent_id = 7

Geben Sie true zurück, wenn in der Tabelle weitere Körbe mit genau 2 Elementen vorhanden sind, wobei ein Element eine shop_week_id = 13 und location_id = 103 und das andere eine shop_week_id = 13 und location_id = 204 hat. Andernfalls geben Sie false zurück.

Wie würden Sie dieses Problem angehen? Das ist selbstverständlich, aber ich suche nach einer sehr effizienten Lösung.

    
keruilin 25.09.2011, 00:48
quelle

3 Antworten

0

Um meine Abfrage zu verdeutlichen, und eine etwas vage Beschreibung der Tabellenspalten der "käuflichen" Tabelle, ist die "Parent_ID" der fragliche Warenkorb. Die "Shop_Week_ID" ist die Gegenleistung für zu vergleichende Körbe ... Vergleichen Sie keinen Korb von Woche 1 bis Woche 2 bis Woche 3. Die # ID-Spalte scheint eine fortlaufende ID in der Tabelle zu sein, aber nicht die tatsächliche ID des zu vergleichenden Artikels ... Die Location_ID scheint das gemeinsame "Item" zu sein. In dem Szenario wird unter Annahme eines Einkaufswagens Location_ID = 103="Computer", Location_ID = 204="Television" (nur für meine Interpretation der Daten). Wenn dies nicht korrekt ist, können geringfügige Anpassungen erforderlich sein, zusätzlich zu dem ursprünglichen Poster, das eine Liste von ... ein Dutzend Dateneinträgen zeigt, um eine korrekte Korrelation zu zeigen.

Also, jetzt, zu meiner Frage .. Ich mache ein STRAIGHT_JOIN, also schließt es sich in der Reihenfolge an, die ich aufgelistet habe.

Die erste Abfrage nach dem Alias ​​"MainBasket" wird ausschließlich dazu verwendet, abzufragen, wie viele Artikel in dem fraglichen Warenkorb ONCE sind, so dass sie nicht erneut für jeden passenden Korb neu angefügt / abgefragt werden muss. Es gibt keine "ON" -Klausel, da dies ein einzelner Datensatz und somit keine kartesische Auswirkung ist, da dieser COUNT (*) - Wert auf JEDEN Datensatz im Endergebnis angewendet werden soll.

Die NEXT-Abfrage soll einen DISTINCT ANDEREN Korb finden, wo mindestens eine "Location_ID" (Artikel) innerhalb der gleichen Woche wie der fragliche Elternteil ist ... Dies könnte dazu führen, dass andere Körbe 1, dieselben oder mehr Einträge als die haben Korb. Wenn es jedoch 100 Körbe gibt, aber nur 18 haben mindestens einen Eintrag, der mit einem Element im ursprünglichen Warenkorb übereinstimmt, haben Sie die Anzahl der Körbe, für die der finale Vergleich durchgeführt wird, deutlich reduziert (SameWeekSimilar-Alias-Ergebnis).

Endlich ist wieder ein Join am käuflichen Tisch, aber basierend auf einem Join für das SameWeekSimilar, aber nur für einen "anderen" Korb, der eine enge Übereinstimmung hatte ... Keine spezifischen Gegenstände, nur durch den Korb. Die Abfrage, mit der das SameWeekSimilar bereits in derselben Woche vorqualifiziert wurde, und mindestens ein übereinstimmendes Element aus dem ursprünglichen Warenkorb, aber den ursprünglichen Warenkorb ausgeschlossen, sodass es nicht mit sich selbst verglichen wird.

Indem wir eine Gruppe auf der äußeren Ebene basierend auf SameWeekSimilar.NextBasket erstellen, können wir die Anzahl der tatsächlichen Artikel für diesen Warenkorb ermitteln. Da eine einfache kartesische Verbindung zur MainBasket besteht, nehmen wir einfach die ursprüngliche Anzahl.

Schließlich die HAVING-Klausel. Da dies NACH dem "COUNT (*)" angewendet wird, wissen wir, wie viele Gegenstände in den Körben "Andere" waren und wie viele im Korb "Haupt". Also enthält die HAVING-Klausel nur diejenigen, bei denen die Zählungen gleich waren.

Wenn Sie testen wollen, was ich beschreibe, führen Sie dies gegen Ihre Tabelle aus, aber schließen Sie die HAVING-Klausel NICHT ein. Sie werden sehen, welche alle MÖGLICH waren ... Dann fügen Sie die HAVING-Klausel erneut hinzu und sehen Sie, welche die gleiche Anzahl haben ...

%Vor%     
DRapp 02.10.2011, 01:46
quelle
3

Die folgende SQL scheint den Trick zu machen

%Vor%

Mit ActiveRecord erhalten Sie dieses Ergebnis mit select_value :

%Vor%

Ich bin jedoch nicht so sicher über die Leistung

    
axelarge 25.09.2011 03:51
quelle
1

Wenn Sie dies so effizient wie möglich gestalten möchten, sollten Sie einen Hash erstellen, der den Inhalt des Korbs als einzelne Zeichenfolge oder Blob codiert. Fügen Sie eine neue Spalte hinzu, die den Hash enthält (der jedes Mal aktualisiert werden muss, wenn der Inhalt des Korbes aktualisiert wird ändern Sie entweder durch die App oder mithilfe eines Triggers), und vergleichen Sie Hash-Werte, um mögliche Gleichheit zu bestimmen. Dann müssen Sie möglicherweise weitere Vergleiche (wie oben beschrieben) in der Reihenfolge durchführen

Was sollten Sie für einen Hash verwenden? Wenn Sie wissen, dass die Körbe in der Größe begrenzt sind, und die fraglichen IDs beschränkte Integer sind, sollten Sie in der Lage sein, zu einer Zeichenkette zu hashen, die genug ist, um auf Gleichheit zu prüfen. Beispielsweise könnten Sie base64 jede shop_week und jeden Standort codieren, mit einem Trennzeichen verknüpfen, das nicht in base64 enthalten ist (wie "|"), und dann mit den anderen Warenkorbelementen verketten. Erstellen Sie einen Index für den neuen Hash-Schlüssel, und die Vergleiche sind schnell.

    
Mike Sokolov 04.10.2011 01:56
quelle