2012-07-12 66 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