1つのオプションは、クロージャーテーブルの使用です。
CREATE TABLE category_closure (
`a_catagory_id` SMALLINT UNSIGNED NOT NULL,
`d_category_id` SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (`a_category_id`,`d_category_id`)
) ENGINE=InnoDB
この表には、階層内のさまざまなレベルのカテゴリ間の関係が記録されています。 a_category_id
は関係の祖先を表し、は子孫を表します。
表が正しく機能するためには、各カテゴリを祖先と子孫として表に入力する必要があります。
INSERT INTO category_closure
(a_category_id, d_category_id)
SELECT
id_category,
id_category
FROM ps_category
その後、各カテゴリにid_parent
欄からご既知の関係を入力することができます。
INSERT INTO category_closure
(a_category_id, d_category_id)
SELECT
id_parent,
id_category
FROM ps_category
WHERE id_parent IS NOT NULL
最後に、ドットを接続する必要があります。 do..while
ループで次のSELECTを実行します。行が返される限り、これらの行をクロージャーテーブルに挿入してループを続行します。このクエリは何
SELECT
cc1.a_category_id,
cc2.d_category_id
FROM category_closure cc1
INNER JOIN category_closure cc2
ON cc2.a_category_id = cc1.d_category_id
LEFT OUTER JOIN category_closure missing_cc
ON missing_cc.a_category_id = cc1.a_category_id
AND missing_cc.d_category_id = cc2.d_category_id
WHERE missing_cc.a_category_id IS NULL
は、それがすべての既存の関係をとりであり、また、存在しなければならないものを見つけました。たとえば、次のようなチェーンを持っている:
53> 67あなたが最初の2つの挿入から、次のレコードを持っています意味> 50
: (50,50) (67,67) (53,53) (50,67) (67,53) (およびその他)。
53が50の子孫であるため、ここでは(50,53)が必要です。上記のSELECTクエリでは、cc1
は(50,67)レコードと一致します。 cc2
は(67,53)レコードと一致します。これは、missing_cc
がcc1
(a_category_id
)から53と、cc2
(d_category_id
)の53と一致するように試みていることを意味します。
最初にこのようなレコードが存在しないため、SELECTステートメントはこれらの2つの行を戻し、挿入して繰り返すことができます。今度は、チェーンの上に行く。あなた(またはあなたのプログラム)がそこにいくつの層があるかを知る必要はなく、SELECTがそれ以上の結果を見つけなくなるまで続行します。
あなたの閉鎖テーブルが構築されると最後に、あなたは、関連する情報を選択することができます。
SELECT
p.id_product,
c.id_category,
GROUP_CONCAT(cc.a_category_id) AS parent_category_ids
FROM ps_category c
LEFT OUTER JOIN ps_product p
ON p.id_category_default = c.id_category
LEFT OUTER JOIN category_closure cc
ON cc.d_category_id = c.id_category
AND cc.a_category_id != c.id_category
GROUP BY c.id_category, p.id_product
これは、すべてのカテゴリを選択し、各カテゴリ内のすべての製品、およびその後、先祖カテゴリのカンマ区切りのリストを提供しますそれらの組み合わせのそれぞれについて。
これは、カテゴリとその祖先を製品とは別に実行するだけなので、実際はかなりの情報が繰り返されていますが、このデータをどのように使いたいか、クエリーかどうか。
注:カテゴリを追加および削除する場合は、現在の閉鎖エントリをすべて削除した後で、カテゴリごとにこの手順を繰り返す必要があります。ここに示すよりも良い方法があり、そのような方法でも(特に階層が非周期的な場合は)id_parent
列の使用を中止することさえできますが、そのようなことはこの質問の範囲外です。
この回答は、アプリケーションや既存のデータを変更することなく、何か試してみる必要があります。
0.8マイクロ秒は非常に高速です。なぜ、より最適化されたソリューションを探しているのですか? – Shadow
@ Shadow、統計情報を変更しました –
あなたのお望みのものはうまくいきますし、最適化はほとんどできません。アプリケーションに応じて(新製品がデータベースに追加される頻度)、MATERIALIZED VIEWを設定することができます。このコンセプトはMySQLには存在しませんが、あなたはそれを模倣することができます:http://www.fromdual.com/mysql-materialized-views –