1

アップデート

私の最終目標は、カテゴリ内の製品の有効期限によってカテゴリをソートすることでした. そのため、有効期限が最も近い製品のカテゴリが最初になり、すべての製品の有効期限が切れたカテゴリが最後になります。グレッグのおかげで、質問の下部にある完全な回答を参照してください。

/アップデート

これは、2 行目を除いて正常に動作します (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でこれを探していて、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 はサブクエリに存在しません。

その条件はメイン クエリの外部結合の一部であるため、その条件は既に true であることがわかっているか、null と評価されて null の結果になります。あなたのサンプル データは、とにかく外部結合を必要としないことを示唆しており、多くの行に将来の有効期限があることがわかります。

これをサブクエリとして書くつもりだったと思います。私たちが得た他の情報のいくつかは、それがまだ最終的な解決策ではないことを示唆していますが、試してみる価値があるかもしれません.

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

EDIT 提案したばかりの変更を行いますが、GROUP BY 句も削除します。

編集2

1)単一の製品テーブルに属する可能性のある複数のテーブルに属性があるようです。それには十分な理由があると思います。

2) Mysql では集計列と非集計列を混在させることができますが、これは悪い習慣であり、私の理論が正しいと証明された場合、それが私たち全員がしばらく困惑した理由の大きな部分を占めていました.

3)すべての左外部結合は、通常は内部結合を使用することを行っているようです。初めてこれを正しく行うことを後悔することはありません。

4)有効期限は、最初に書いた方法でサブクエリを介して検索するか、他の回答で行われた別の結合として検索できます。そこに本当に 1 対 1 の関係がある場合、MIN() と GROUP BY は必要なく、誰かを混乱させる可能性があります。(実際には、編集 #3 を参照してください。)

5)サブクエリは、有効期限が過去にある製品に対して null と評価されるため、2 番目の列で 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 の最小日付 >= 現在の日付/時刻がないため、null 列が存在します。製品 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 に答える