Erstellen Sie SQL-Abfrage, dass Aufträge Ergebnisse von welchem ​​Zustand sie sich treffen

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

  •  19-08-2019
  •  | 
  •  

Frage

Dies ist für MySQL und PHP

Ich habe eine Tabelle, die die folgenden Spalten enthält:

navigation_id (unsigned int primary key)
navigation_category (unsigned int)
navigation_path (varchar (256))
navigation_is_active (bool)
navigation_store_id (unsigned int index)

Die Daten werden wie gefüllt werden:

1, 32, "4/32/", 1, 32
2, 33, "4/32/33/", 1, 32
3, 34, "4/32/33/34/", 1, 32
4, 35, "4/32/33/35/", 1, 32
5, 36, "4/32/33/36/", 1, 32
6, 37, "4/37/", 1, 32
... another group that is under the "4/37" node
... and so on

So wird dies einen Baum wie Struktur darstellen. Mein Ziel ist es, eine SQL-Abfrage zu schreiben, die die Filial-ID von 32 und Kategorie-ID von 33, kehrt gegeben,

Als erstes wird eine Gruppe von Elementen, die die Eltern der Kategorie 33 (in diesem Fall 4 und 32)

sind

Dann wird eine Gruppe von Elementen, die ein Kind der Klasse 33 (in diesem Fall 34, 35, und 36)

Dann wird der Rest der "root" Kategorien unter der Kategorie 4 (in diesem Fall 37).

So ist die folgende Abfrage die korrekten Ergebnisse zurück:

SELECT * FROM navigation 
WHERE navigation_store_id = 32 
AND (navigation_category IN (4, 32) 
    OR navigation_path LIKE "4/32/33/%/" 
    OR (navigation_path LIKE "4/%/" 
        AND navigation_category <> 32))

Mein Problem ist, dass ich die „Gruppen“ von Kategorien in der oben angegebenen Reihenfolge bestellen möchten (Eltern von 33 ersten, Kinder von 33 Sekunden, und die Eltern des Root-Knotens zuletzt). Also, wenn sie die erste Bedingung erfüllen, bestellen sie zuerst, wenn sie die zweite Bedingung, um sie zweite erfüllen und wenn sie sich treffen die dritte (und vierte) Zustand, um sie schließlich.

Sie können ein Beispiel dafür, wie die Kategoriestruktur funktioniert an dieser Stelle:

www.eanacortes.net

Sie können feststellen, dass es ziemlich langsam. Die aktuelle Art, wie ich tue dies, ich magento ursprüngliche Kategorie Tabelle verwenden und Ausführen von drei besonders langsamen Abfragen darauf; dann die Zusammenstellung der Ergebnisse in PHP. Mit dieser neuen Tabelle Ich bin die Lösung ein weiteres Problem, das ich mit magento, sondern würde auch meine Leistung wie zur gleichen Zeit zu verbessern. Der beste Weg, ich sehe dies erreicht wird, ist dabei alle drei Abfragen zusammen und mit weniger PHP Arbeit durch die Ergebnisse richtig sortiert hat.

Danke

Bearbeiten

In Ordnung, es funktioniert jetzt groß. Schneiden Sie es von 4 Sekunden nach unten bis zu 500 MS. Große Geschwindigkeit jetzt:)

Hier ist mein Code in der Colleciton Klasse:

    function addCategoryFilter($cat)
    {
        $path = $cat->getPath();
        $select = $this->getSelect();
        $id = $cat->getId();
        $root = Mage::app()->getStore()->getRootCategoryId();
        $commaPath = implode(", ", explode("/", $path));

        $where = new Zend_Db_Expr(
            "(navigation_category IN ({$commaPath}) 
                    OR navigation_parent = {$id}
                    OR (navigation_parent = {$root}
                    AND navigation_category <> {$cat->getId()}))");

        $order = new Zend_Db_Expr("
                CASE
                    WHEN navigation_category IN ({$commaPath})  THEN 1
                    WHEN navigation_parent = {$id} THEN 2
                    ELSE 3
                END, LENGTH(navigation_path), navigation_name");

        $select->where($where)->order($order);
        return $this;
    }

Dann verbrauchen ich es mit dem folgenden Code in meiner Kategorie Block gefunden:

        // get our data
        $navigation = Mage::getModel("navigation/navigation")->getCollection();
        $navigation->
            addStoreFilter(Mage::app()->getStore()->getId())->
            addCategoryFilter($currentCat);

        // put it in an array
        $node = &$tree;
        $navArray = array();
        foreach ($navigation as $cat)
        {
            $navArray[] = $cat;
        }
        $navCount = count($navArray);

        $i = 0;

        // skip passed the root category
        for (; $i < $navCount; $i++)
        {
            if ($navArray[$i]->getNavigationCategory() == $root)
            {
                $i++;
                break;
            }
        }

        // add the parents of the current category
        for (; $i < $navCount; $i++)
        {
            $cat = $navArray[$i];

            $node[] = array("cat" => $cat, "children" => array(), 
                "selected" => ($cat->getNavigationCategory() == $currentCat->getId()));
            $node = &$node[0]["children"];

            if ($cat->getNavigationCategory() == $currentCat->getId())
            {
                $i++;
                break;
            }
        }

        // add the children of the current category
        for (; $i < $navCount; $i++)
        {
            $cat = $navArray[$i];
            $path = explode("/", $cat->getNavigationPath());
            if ($path[count($path) - 3] != $currentCat->getId())
            {
                break;
            }

            $node[] = array("cat" => $cat, "children" => array(), 
                "selected" => ($cat->getNavigationCategory() == $currentCat->getId()));
        }

        // add the children of the root category
        for (; $i < $navCount; $i++)
        {
            $cat = $navArray[$i];
            $tree[] = array("cat" => $cat, "children" => array(), 
                "selected" => ($cat->getNavigationCategory() == $currentCat->getId()));
        }

        return $tree;

Wenn ich zwei Antworten akzeptieren kann ich die ersten und letzten annehmen würde, und wenn ich eine Antwort akzeptieren könnte als „interessant / nützlich:“ Ich würde das tun, mit dem zweiten. :)

War es hilfreich?

Lösung

Ein CASE Ausdruck sollte den Trick tun.

SELECT * FROM navigation 
    WHERE navigation_store_id = 32 
        AND (navigation_category IN (4, 32) 
            OR navigation_path LIKE "4/32/33/%/" 
            OR (navigation_path LIKE "4/%/" 
            AND navigation_category <> 32))
    ORDER BY
        CASE
            WHEN navigation_category IN (4, 32) THEN 1
            WHEN navigation_path LIKE "4/32/33/%/" THEN 2
            ELSE 3
        END, navigation_path

Andere Tipps

Versuchen Sie, eine zusätzliche abgeleitete Spalte wie "Gewicht":

(ungetestet)

(IF(criteriaA,1,0)) + (IF(criteriaB,1,0)) ... AS weight
....
ORDER BY weight 

Jede Kriterien erhöht die „Gewicht“ des Art. Sie könnten auch die Gewichte deutlich durch Verschachtelung IFs und geben Sie die Gruppen eine bestimmte ganze Zahl eingestellt sortieren nach wie:

IF(criteriaA,0, IF(criteriaB,1, IF ... )) AS weight

Ist MySQL die UNION SQL Keyword-Abfragen zu kombinieren? Ihre drei Fragen haben in erster Linie nicht überlappende Kriterien, so dass ich vermute, es ist am besten, sie als im wesentlichen separaten Abfragen zu verlassen, aber kombinieren sie UNION oder UNION ALL verwenden. Dies wird 2 DB Umläufe speichern und möglicherweise für die MySQL-Anfrageplaner erleichtern zu „sehen“ die beste Art und Weise jeden Satz von Zeilen zu finden ist.

Durch die Art und Weise, Ihre Strategie, um den Baum zu vertreten durch Pfade von der Wurzel zu speichern ist einfach zu kippen zu folgen, sondern eher ineffizient, wenn Sie eine WHERE-Klausel der Form navigation_path like '%XYZ' verwenden müssen - auf allen DBs ich gesehen habe, LIKE Bedingungen müssen mit einer nicht-Wildcard starten Verwendung eines Index auf dieser Spalte zu ermöglichen. (In Ihrem Beispiel-Code-Snippet, müssten Sie eine solche Klausel, wenn Sie nicht bereits wissen, dass die Wurzel der Kategorie 4 war (Wie wussten Sie, dass durch die Art und Weise? Von einem separaten, früheren Abfrage?))

Wie oft ändern Sie Ihre Kategorien? Wenn sie nicht oft ändern, können Sie Ihren Baum repräsentieren die „verschachtelte Sätze“ Methode, beschrieben hier , die.

„Nachkommen / Vorfahren einer bestimmten Kategorie sind, welche Kategorien“ viel schneller Abfragen auf Dinge wie ermöglicht
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top