2

特定の製品が含まれるカテゴリのリストを取得するためのクエリを見つけようとしています。

私は、categories、product_to_sec_cat_assoc、およびproductsという3つのテーブルを持つproductsというデータベースを持っています。

+--------------------+ +--------------------+ +--------------------------+
| Products           | | categories         | | product_to_sec_cat_assoc |
+--------------------+ +--------------------+ +--------------------------+
| product_id         | | category_id        | | product_id               |
| pri_category_id    | | category_name      | | category_id              |
| name               | | url_link           | +--------------------------+
+--------------------+ +--------------------+ 

すべての製品にセカンダリカテゴリがあるわけではないため、製品エントリでそのプライマリカテゴリを製品に直接割り当てています。それらが他のセカンダリカテゴリにもある場合は、product_to_sec_cat_assocという関連付けテーブルを使用して、さらにカテゴリを関連付けます。

特定のカテゴリのすべての製品を表示するページを作成したいというクエリの作成に問題があります。各製品リストには、それらが属するさまざまな二次カテゴリも表示されます。

私の現在のクエリは次のとおりです。

select t.*, 
GROUP_CONCAT(c.category_name order by pri_category_id, c.category_id) as category_names, 
GROUP_CONCAT(c.url_link) as category_links from products t
left join product_to_sec_category_assoc a using (id)
left join categories c on t.pri_category_id = c.category_id or c.category_id = a.category_id
where t.pri_category_id = 12 
or (a.category_id = 12 and a.id = t.id)
group by t.title

ただし、何らかの理由で、商品を複数のセカンダリカテゴリに追加した場合、いずれかのセカンダリカテゴリの商品を表示すると、表示しているプラ​​イマリカテゴリとセカンダリカテゴリのみが表示されます。一方、プライマリカテゴリのリストを表示すると、プライマリカテゴリとそのすべてのセカンダリカテゴリが表示されます。

たとえば、iPadが電子機器のプライマリカテゴリにあり、タブレットとモバイルのセカンダリカテゴリにあるとします。エレクトロニクスのカテゴリリストにアクセスすると、iPadがエレクトロニクス、タブレット、モバイルで表示されます。モバイルカテゴリに入ると、電子機器、モバイルに表示されます。タブレットのカテゴリに入ると、電子機器、タブレットのカテゴリに表示されます。

私が抱えているもう1つの問題は、クエリがGROUP_CONCAT(category_name)とGROUP_CONCAT(category_link)の順序を正しく設定していないため、category_namesとそれらのリンクが一致する順序になっていることです。

4

1 に答える 1

2

あなたの問題はあなたのデザイン(カテゴリーに対して2つの異なる関係を持つ製品)を考えるとかなりトリッキーです。問題は、WHERE条項で、基本的に残りの製品のカテゴリを除外し、ユーザーが属するカテゴリやそのプライマリカテゴリのみを返すことです。

FROM代わりに、最初にセカンダリカテゴリテーブルまたはプライマリカテゴリフィールド(副選択で実行)のいずれかで特定のカテゴリを持つ製品を選択してから、その結果をセカンダリカテゴリテーブル結合する必要があります。これにより、すべてを取得できます。特定のカテゴリに含まれる製品のみのカテゴリ(プライマリカテゴリであるかどうかに関係なく):

SELECT
    a.*,
    GROUP_CONCAT(DISTINCT CONCAT(c.category_name, '||', c.url_link) ORDER BY c.category_name) AS categories
FROM
    (
        SELECT 
            aa.product_id,
            aa.pri_category_id,
            aa.name
        FROM
            products aa
        LEFT JOIN
            product_to_sec_category_assoc bb ON 
                aa.product_id = bb.product_id
                AND bb.category_id = 12
        WHERE
            aa.pri_category_id = 12
            OR bb.product_id IS NOT NULL
    ) a
LEFT JOIN
    product_to_sec_cat_assoc b ON a.product_id = b.product_id
LEFT JOIN
    categories c ON 
        a.pri_category_id = c.category_id
        OR b.category_id = c.category_id
GROUP BY
    a.product_id
ORDER BY
    a.title

212つのは、ユーザーが属している現在のカテゴリを表します。

注意しなければならないことの1つはOR、2番目LEFT JOINの行は、少なくとも1つのセカンダリカテゴリを持つ製品ごとに常に2つの行を結合することです。1つの行は常にその製品のプライマリカテゴリになります。そのため、視覚的に結合すると、製品にリストされているセカンダリカテゴリごとに、製品のプライマリカテゴリがその上に追加され、重複が発生します。DISTINCTこれが、GROUP_CONCAT()関数に導入する必要がある理由です。

では、とフィールドをで区切ってGROUP_CONCAT()統合することにしました。アプリケーションで使用している言語に応じて、その区切り文字に基づいて2つを分割できます。これは、2つの異なる列の順序を一致させようとするよりも優れています。category_nameurl_link||


おそらく、より良い設計は、製品とカテゴリの間に多対多の関係を持ち、カテゴリがプライマリであるかどうかを示すフィールドを相互参照テーブルに含めることです。スキーマは次のようになります。

+---------------+ +-------------------+ +----------------+
| products      | | product_cat_assoc | | categories     |
+---------------+ +-------------------+ +----------------+
| product_id    | | product_id        | | category_id    |
| name          | | category_id       | | category_name  |
+---------------+ | is_primary        | | url_link       |
                  +-------------------+ +----------------+

これで、2つではなく1つの関係に基づいてカテゴリを取得するだけで済みます。is_primaryフィールドはTINYINT(1)であり、プライマリであるかどうかを含むか、または示すことができます0。この設計では、すべての製品のテーブルに、プライマリカテゴリを表す1対応する行が常に少なくとも1つある必要があります。product_cat_assoc追加の行はセカンダリカテゴリになります。

次に、特定のカテゴリ内の製品のすべてのカテゴリのリストを取得するには、クエリは次のように簡単になります。

SELECT
    a.*,
    GROUP_CONCAT(CONCAT(c.category_name, '||', c.url_link) ORDER BY b.is_primary DESC) AS categories
FROM
    (
        SELECT 
            aa.product_id, 
            aa.name
        FROM 
            products aa
        INNER JOIN 
            product_cat_assoc bb ON aa.product_id = bb.product_id AND bb.category_id = 12
    ) a
INNER JOIN
    product_cat_assoc b ON a.product_id = b.product_id
INNER JOIN
    categories c ON b.category_id = c.category_id
GROUP BY
    a.product_id
ORDER BY
    a.name
于 2012-06-18T18:33:23.917 に答える