1

更新

我的最终目标是按产品的有效期对类别进行分类。因此,最接近过期的产品类别排在最前面,所有产品都已过期的类别排在最后。感谢 Greg,请参阅问题底部的完整答案。

/更新

除了第二行(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

回答 我的最终目标是得到

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寻找这个并且您正在使用 Categories 模块,然后转到 catalog/model/catalog/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 字段添加到数据库和后端管理面板。

4

2 回答 2

2

我不相信这个说法是真的:

最初的问题在于子查询看不到您在主查询中加入的表。所以 p.product_id 和 p2c.product_id 在子查询中不存在。

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

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

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

编辑 进行我刚才建议的更改,但也要摆脱 GROUP BY 子句。

编辑 2

1)您似乎在可能属于单个产品表的多个表中具有属性。我会假设你有充分的理由这样做。

2) Mysql 允许您混合聚合列和非聚合列,但这是一种不好的做法,如果我的理论被证明是正确的,那是我们都被难住了一会儿的很大一部分原因。

3)所有左外连接似乎都在做你通常使用内连接的事情。你不会后悔第一次就做对了。

4)到期日期可以通过子查询来查找,就像您第一次编写它的方式一样,也可以作为另一个连接来查找,就像另一个答案所做的那样。如果那里确实存在一对一的关系,那么 MIN() 和 GROUP BY 就不是必需的,并且可能会使某些人感到困惑。(事实上​​,参见编辑#3。)

5)由于您的子查询对于任何过期时间为过去的产品评估为 null,因此您可能需要 ORDER BY 第二列或只使用过期日期,无论它是过去还是将来。

编辑 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
于 2012-07-13T01:02:00.267 回答
1

更新答案现在数据样本可用

仍然假设它是 Microsoft 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
于 2012-07-12T23:53:49.427 回答