这是MySQL和PHP

我有一个包含下面的表:

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

数据将被填充,如:

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

因此,这将表示类似结构的树。我的目标是写,鉴于32和33类ID店铺ID的SQL查询,将返回

首先,一组是33的类别的父母元件(在这种情况下4和32)

然后,一组是33类的一个子元素(在此情况下34,35,和36)的

接着的下4类的“根”的类别的其余部分(在此情况下37)。

所以下面的查询将返回正确的结果:

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))

我的问题是,我想订购的类别的“基团”,在上面列出的顺序(第33第一,33秒的孩子的父母,并且根节点最后的父母)。因此,如果它们满足第一条件,第一命令他们,如果符合第二个条件顺序他们第二和如果符合第三(和第四)条件顺序他们最后。

您可以看到的品类结构是如何工作的,在这个网站的例子:

www.eanacortes.net

您可能会注意到,这是相当缓慢的。目前的办法我这样做,我使用Magento的原始类别表,并执行了三种尤其慢查询就可以了;然后把结果放在一起在PHP。使用这个新表,我解决另一个问题,我有Magento的,但也想提高我的同时性能。我看到这是完成最好的办法是把所有三个查询在一起,让PHP工作较少受到有结果排序正确。

由于

修改

好了,现在它的伟大工程。从4秒剪下来下降到500个MS。现在大速度:)

下面是我的代码在Colleciton类:

    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;
    }

然后我消耗它与我的分类块中找到的以下代码:

        // 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;

如果我能接受两个答案我会接受的第一个和最后一个,如果我能接受的答案为“有趣/有用”我会做,随着第二。 :)

有帮助吗?

解决方案

一个CASE表达应该做的伎俩。

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

其他提示

尝试一个附加派生列像 “重量”:

(适用未经测试)

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

每个标准增加了排序的“权重”。 您也可以通过嵌套的IF,并给予组特定的整数像排序设定的权重明显:

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

的MySQL是否有合并查询UNION SQL关键字?你的三个疑问主要有非重叠的标准,所以我怀疑这是最好的给他们留下本质上是单独的查询,但使用UNIONUNION ALL将它们结合起来。这将节省2 DB往返,并可能使其更容易为MySQL的查询规划“看到”找到的每一组行的最好方式是。

顺便说一句,你从根存储路径给小费表示树的策略是容易执行,而是效率低下,当您需要使用表单navigation_path like '%XYZ'的WHERE子句 - 在我见过的所有数据块,LIKE条件必须以非通配符开始以能够使用在该列的索引的。 (在你的示例代码片段,你需要这样的条款,如果你还不知道这根类别为4(你怎么知道的方式?从一个单独的,前面的查询?))

多久你的类别变化?如果他们不经常改变,你可以代表使用“嵌套组”的方法,描述你的树这里,这使得对事物更快的查询,如“哪些类别的后代/特定类别的祖先。”

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top