2012-07-12 67 views
1

UPDATE复杂的排序功能,Opencart的

我的最终目标是通过内部产品的到期日期类别进行排序。因此,产品类别最接近到期​​的类别将首先排到最后。感谢Greg,请参阅问题底部的完整答案。

/UPDATE

这个工程除了第二行精(SELECT MIN(date_expires ...如何改写这一行的任何想法

SELECT c.category_id, 
      name, 
      c.image, 
      description, 
      (SELECT MIN(date_expires) 
      FROM  product 
      WHERE date_expires >= NOW() AND 
       p.product_id = p2c.product_id) AS expiring 
FROM category c 
     LEFT JOIN category_description cd 
      ON (c.category_id = cd.category_id) 
     LEFT JOIN product_to_category p2c 
      ON (c.category_id = p2c.category_id) 
     LEFT JOIN product p 
      ON (p2c.product_id = p.product_id) 
WHERE c.parent_id = 0 AND c.status = '1' 
GROUP BY c.category_id 
ORDER BY expiring 

一些样本数据:

category: 
category_id = 62 
category_id = 64 
category_id = 63 

product_to_category: 
product_id = 43 category_id = 62 
product_id = 50 category_id = 63 
product_id = 56 category_id = 63 
product_id = 58 category_id = 62 
product_id = 59 category_id = 63 
product_id = 60 category_id = 63 
product_id = 61 category_id = 63 
product_id = 62 category_id = 63 
product_id = 63 category_id = 64 

product: 
product_id = 43 date_expires = 2012-07-11 20:35:00 
product_id = 50 date_expires = 2012-06-29 00:00:00 
product_id = 56 date_expires = 2012-07-13 00:00:00 
product_id = 58 date_expires = 2012-07-26 15:01:00 
product_id = 59 date_expires = 2012-07-16 14:12:00 
product_id = 60 date_expires = 2012-07-18 08:15:00 
product_id = 61 date_expires = 2012-08-02 13:04:00 
product_id = 62 date_expires = 2012-08-24 00:00:00 
product_id = 63 date_expires = 2012-07-12 19:16:00 

ANSWER 我最终的目标是得到

SELECT c.category_id, minDateExpires.Expiring, 
CASE WHEN Expiring > 1 THEN 1 ELSE 2 END as available 
FROM category c 
LEFT JOIN product_to_category p2c ON (c.category_id = p2c.category_id) 
LEFT JOIN product p ON (p2c.product_id = p.product_id) 
LEFT JOIN ( 
    SELECT MIN(date_expires) AS expiring, category_id FROM product p join product_to_category p2c on p2c.product_id = p.product_id WHERE date_expires >= GETDATE() GROUP BY category_id 
) minDateExpires on p2c.category_id = minDateExpires.category_id 
ORDER BY available, expiring 

如果您正在寻找此为Opencart的特别是和你使用的是分类模块然后进入目录/模型/目录/ category.php和编辑功能getCategoriesPag()来:

public function getCategoriesPag($data) { 
     $query = $this->db->query("SELECT c.category_id, name, c.image, description, minDateExpires.Expiring, CASE WHEN Expiring > 1 THEN 1 ELSE 2 END as available FROM " . DB_PREFIX . "category c LEFT JOIN " . DB_PREFIX . "category_description cd ON (c.category_id = cd.category_id) LEFT JOIN " . DB_PREFIX . "category_to_store c2s ON (c.category_id = c2s.category_id) LEFT JOIN " . DB_PREFIX . "product_to_category p2c ON (c.category_id = p2c.category_id) LEFT JOIN " . DB_PREFIX . "product p ON (p2c.product_id = p.product_id) LEFT JOIN (SELECT MIN(date_expires) AS expiring, category_id FROM product p JOIN product_to_category p2c on p2c.product_id = p.product_id WHERE date_expires >= NOW() GROUP BY category_id) minDateExpires on p2c.category_id = minDateExpires.category_id WHERE c.parent_id = 0 AND cd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND c2s.store_id = '" . (int)$this->config->get('config_store_id') . "' AND c.status = '1' GROUP BY c.category_id ORDER BY available, Expiring, c.sort_order"); 

     return $query->rows; 
    } 

您需要将自己的date_expires字段添加到数据库和后端管理面板。

+1

什么不工作有关问题的路线?你有什么错误吗?你有什么尝试?这应该是DBMS不可知论的,还是针对特定的DBMS? – Jim 2012-07-12 23:53:47

+0

@Jim不知道DBMS是什么,它是从Opencart上基于PHP的网站搜索。我没有遇到任何错误,但我也没有从特定行中得到任何结果。我已经尝试了所有我能用这种方法想到的事情,并且通过使用CASE,也没有取得任何成功。 – Cleverbot 2012-07-13 00:04:18

回答

1

更新到现在答案THAT DATA可提供样品

仍然假设它是微软的SQL Server,此查询产生以下结果

SELECT c.category_id, minDateExpires.Expiring 
FROM category c 
LEFT JOIN product_to_category p2c ON (c.category_id = p2c.category_id) 
LEFT JOIN product p ON (p2c.product_id = p.product_id) 
LEFT JOIN ( 
    SELECT MIN(date_expires) AS expiring, Product_ID FROM product WHERE date_expires >= GETDATE() GROUP BY Product_ID 
) minDateExpires on p.product_id = minDateExpires.product_id 
ORDER BY expiring 

结果:

category_id Expiring 
63  NULL 
63  NULL 
62  NULL 
64  NULL 
63  2012-07-16 14:12:00.000 
63  2012-07-18 08:15:00.000 
62  2012-07-26 15:01:00.000 
63  2012-08-02 13:04:00.000 
63  2012-08-24 00:00:00.000 

空列因为这些产品ID没有最短日期> =当前日期/时间。实际上,您是否按照分类ID分组的最短日期时间,而不是产品ID?在这种情况下,你的查询可以是这样的:

SELECT c.category_id, minDateExpires.Expiring 
FROM @category c 
LEFT JOIN @product_to_category p2c ON (c.category_id = p2c.category_id) 
LEFT JOIN @product p ON (p2c.product_id = p.product_id) 
LEFT JOIN ( 
    SELECT MIN(date_expires) AS expiring, Category_ID FROM @product p join @product_to_category p2c on p2c.product_id = p.product_id WHERE date_expires >= GETDATE() GROUP BY Category_id 
) minDateExpires on p2c.category_id = minDateExpires.category_id 
ORDER BY expiring 

,让你

64 NULL 
63 2012-07-16 14:12:00.000 
63 2012-07-16 14:12:00.000 
63 2012-07-16 14:12:00.000 
63 2012-07-16 14:12:00.000 
63 2012-07-16 14:12:00.000 
63 2012-07-16 14:12:00.000 
62 2012-07-26 15:01:00.000 
62 2012-07-26 15:01:00.000 
+0

哇这是令人印象深刻的东西谢谢。子查询中还有一个额外的支架,这远远超过我的头。 – Cleverbot 2012-07-13 00:11:31

+0

对不起,忘了取出那里的最后一个支架。现在更新 – Greg 2012-07-13 00:12:46

+0

嗯,它仍然没有为我带来结果。我尝试将第一个'minDateExpires.Expiring'更改为'minDateExpires.expiring',然后我也尝试更改'ORDER BY minDateExpires.expiring'并且都没有工作... – Cleverbot 2012-07-13 00:19:16

2

我不相信这种说法是正确的:

原来的问题就在于子查询无法看到您在主查询中加入的表。因此,子查询中不存在p.product_id和p2c.product_id。

由于该条件是主查询中外连接的一部分,因此该条件已知为true或将计算为null,从而导致空结果。现在您的示例数据表明您无论如何都不需要外部连接,并且我可以看到许多行中都有未来的到期日期。

我相信你的意思是把它写成你的子查询。尽管我们得到的其他信息表明它仍然不是最终的解决方案,但值得一试。

(
SELECT MIN(date_expires) 
FROM product as p2 
WHERE date_expires >= NOW() AND 
     p2.product_id = p.product_id 
) AS expiring 

编辑 让我建议的变化,同时也摆脱了GROUP BY子句。

EDIT 2

1)你似乎有可能在一个单一的产品表属于多个表的属性。我会假设你有很好的理由。

2) MySQL允许你混合骨料和非集合列,但是这是一个不好的做法,如果我的理论被证实是真的,那是的我们都难倒了一小会儿的很大一部分原因。

3)所有的左外连接似乎都在做你通常使用内连接的方式。你不会后悔第一次做这件事。

4)过期日期可以通过子查询的方式来查找您第一次写它的方式或作为另一个连接完成的另一个答案。如果在那里真的存在一对一的关系,那么MIN()和GROUP BY就没有必要,并且可能会混淆某人。 (事实上​​,看到编辑#3)

5)由于您的子查询评估与过期下降,在过去的任何产品为空,则可能需要按第二列或只使用截止日期不管它是过去还是未来。

编辑3

SELECT 
    c.category_id, 
    MIN(name) as name, 
    c.image /* better as a subquery if you can't do an aggregate on a LOB */ 
    MIN(c.description) as description, 

    /* don't even need the subquery because you've already joined the product table */ 
    CASE 
     WHEN MIN(p.date_expires) >= NOW() THEN MIN(p.date_expires) 
     ELSE NULL /* this may not be what you really wanted */ 
    END as expiring_my_first_guess, 

    /* what was really intended */ 
    MIN(CASE WHEN p.date_expires >= NOW() THEN p.date_expires ELSE NULL END) as expiring, 

FROM category c 
    INNER JOIN category_description cd 
     ON (c.category_id = cd.category_id) 
    INNER JOIN product_to_category p2c 
     ON (c.category_id = p2c.category_id) 
    INNER JOIN JOIN product p 
     ON (p2c.product_id = p.product_id) 
WHERE c.parent_id = 0 AND c.status = '1' 
GROUP BY c.category_id 
ORDER BY expiring 
+0

我认为你的GROUP BY搞砸了。尝试摆脱它。这可能意味着你正在使用MySQL,顺便说一句。 – shawnt00 2012-07-13 01:04:33

+0

是的,这是有道理的,我使用GROUP BY只是因为我认为我必须。我正在使用foreach($ categories作为$ category)来输出结果。我会在几个小时内尝试您的建议,感谢您的意见! – Cleverbot 2012-07-13 01:15:17

+0

你是对的,你可以保留当前的子选择。不知道我在那里想什么。我仍然喜欢加入到一个子选择,而不是在选择,但都工作。同意摆脱集团 – Greg 2012-07-13 01:26:05