分離した2つの製品フィルターセット$special_filters
と$other_filters
があります。 $special_filters
のいずれかのフィルターと$other_filters
のいずれかのフィルターに一致する製品をデータベースから取得しようとしています。たとえば、$special_filters = {'New'}
および$other_filters = {'Brakes', 'Tires'}
の場合、すべての新しい部品、すべてのブレーキ、およびすべてのタイヤではなく、すべての新しいブレーキおよびすべての新しいタイヤを入手したいと考えています。これが私がphpMyAdminで機能させたものです(ここでproduct_filters
テーブルはproduct_id
とfilter_id
を関連付ける2列のテーブルです:
SELECT q.product_id FROM (
SELECT product_id FROM `<prefix>_j2store_product_filters`
WHERE filter_id = 'tag1'
) AS q
INNER JOIN `<prefix>_j2store_product_filters` AS t ON q.product_id = t.product_id
WHERE filter_id IN ('tag2', 'tag3')
これにより、tag1
、およびtag2
またはtag3
のいずれかを含むすべての製品が正常に検出されます。しかし、Joomlaへの翻訳が機能していないようです。
administrator/components/com_j2store/models/products.php
関数の終わり近くにある_sfBuildWhereQuery
のJ2Storeのコードを変更しています。これは、製品のリストを取得するJDatabaseクエリオブジェクトを設定しています。コードのこの時点で、アクティブなすべてのフィルターを含み、2つのフィルター配列の和集合である$filter_ids
配列があります。適切な "WHERE"句を現在のクエリオブジェクトに追加する必要があります。私は基本的に自分のSQLコードをJDatabaseに変換しようとしました。これが私の試みです:
$other_ids = array_diff($filter_ids, $special_filters);
if (empty($special_filters) || empty($other_ids)) {
// This is the usual case for the 'OR' operator.
$query->where ( '#__j2store_product_filters.filter_id IN ('
. implode ( ',', $filter_ids ) . ')' );
} else {
// Make sub-sub-query to filter with special filters
$subSubQuery = $db->getQuery(True);
$subSubQuery
->select($db->quoteName('product_id'))
->from($db->quoteName('#__j2store_product_filters'))
->where($db->quoteName('filter_id')
. ' IN (' . implode(',', $special_filters) . ')');
// Filter the result with the other filters in another subquery
$subQuery = $db->getQuery(True);
$subQuery
->select($db->quoteName('s.product_id'))
->from($subSubQuery, 's')
->join('INNER',
$db->quoteName('#__j2store_product_filters', 'f')
. ' ON (' . $db->quoteName('s.product_id')
. ' = ' . $db->quoteName('f.product_id') . ')')
->where($db->quoteName('filter_id')
. ' IN (' . implode(',', $other_ids) . ')');
$query->where('EXISTS (SELECT * FROM (' . $subQuery->__toString() . ') AS t
WHERE ' . $db->quoteName('#__j2store_product_filters.product_id') .
' = ' . $db->quoteName('t.product_id') . ')');
}
ただし、結果が多すぎます。新しいブレーキと新しいタイヤだけでなく、すべての新しい部品、すべてのブレーキ、すべてのタイヤがまだ返されています。
これは私が必要とする条件付きロジックのデモです:db-fiddle.com/f/o1UWTKXVTxxwyvrpcupmqu/3
GROUP BY item
のほうが適しています。次に、HAVING句を使用して、集計データに対して条件付きのid_filters
、special_filters
、およびother_filters
条件を実行します。
Db-fiddleデモについて...
SELECT
item
FROM item_tags
GROUP BY item
HAVING
MAX(CASE WHEN tag IN ('Used') THEN 1 ELSE NULL END)
AND MAX(CASE WHEN tag IN ('Brake') THEN 1 ELSE NULL END)
NULL
の結果が「偽」であるのに対して、満足のいく結果は「真実」でなければならないため、1
は単に使用されます。両方の条件が非nullと評価された場合、対象となるitem
があります。簡単できれい。
さて、マイクロ最適化が必要な場合は、2つのフィルタリングリストを1つの文字列にマージして追加すると、次のような利点があります。
WHERE tag IN ($all_csv_filters_as_one)
ベンチマークするための現実的なデータがなかったので、この追加の句は調査しませんでした(そして、そうすることにあまり関心がありません)。これはHAVING句を置き換えるのではなく、「集約」データを事前にフィルタリングするので、HAVINGはそれほど多くのことを調べる必要がないことに注意してください。
J2storeクエリのJoomlaクエリビルダーの構文は次のようになります。
$query = $db->getQuery(true)
->select("product_id")
->from("#__j2store_product_filters")
->group("product_id")
->having([
"MAX(CASE WHEN filter_id IN ({$filter_ids}) THEN 1 ELSE NULL END)",
"MAX(CASE WHEN filter_id IN ({$special_filter_ids}) THEN 1 ELSE NULL END")
]);
pS.
それぞれのフィルターが空の文字列でないかどうかに応じて、条件付きでさらにHAVING句を追加する場合は、1つ以上のfilter_id
値を含めるたびに、条件付きで新しいHAVINGメソッドを呼び出すことができます。このような...
// build $query with all of the other clauses then after ->group()...
if ($filter_ids)
{
$query->having("MAX(CASE WHEN filter_id IN ({$filter_ids}) THEN 1 ELSE NULL END)");
}
if ($special_ids)
{
$query->having("MAX(CASE WHEN filter_id IN ({$special_ids}) THEN 1 ELSE NULL END)");
}
if ($other_ids)
{
$query->having("MAX(CASE WHEN filter_id IN ({$other_ids}) THEN 1 ELSE NULL END)");
}
私の問題は実際にはSQLにありませんでした。さらにデバッグを行ったところ、「if empty」句しか入力していないことがわかりました。そのため、デフォルトの動作を行っていました。私の問題は、変数を理解していないことでした
$filter_ids = $state->productfilter_id;
配列だと思いましたが、実はカンマ区切りの文字列です!それを考慮に入れると、私のJoomlaコードは機能しました。
この質問は削除できると思いますが、一方で、上記のコードはこの特定の問題の解決策を提供します。