根据当前选择添加额外的商店过滤器

时间:2018-07-24 08:59:38

标签: mysql laravel filter attributes shop

我有下表(MySQL数据库,表products_attributes):

product_id | attribute_id | attribute_value_id

我拥有可用于过滤表格的当前产品ID(按类别或搜索查询过滤);这将确保我将基于当前已过滤的产品构建所有可用的过滤器。

我的问题是我必须基于当前产品构建过滤器列表,并能够添加一些额外的产品以扩展结果;这些过滤器将来自至少应用n-1个过滤器的产品; n过滤器将是多余的。

示例:

我在“鞋子”类别中,并按颜色(黑色)和尺寸(40)进行过滤;在我的过滤器列表中,我现在得到了颜色:黑色和尺寸:40(已过滤);在这种情况下,我还拥有黑色但尺寸为42的产品。我需要将“ 42”作为可行的选项显示在“大小”过滤器中,因为这会遵循附加过滤器的n-1规则。

我不知道如何在一个SQL查询中执行此操作。这个想法也是在表中查找product_id,该product_id至少具有n-1个所选过滤器作为attribute_value_id。结果应该是一个独特的attribute_values_id集合,其中包含当前过滤条件和其他可行的过滤条件。

也许这更有用:

这是我的过滤条件( attribute_id attribute_value_id ):(1、12)和(6、268)。

这意味着过滤器列表将由所有过滤的产品组成,但没有其他可行的选择。如果运行此命令,那么在这种情况下,我将拥有属于当前类别的所有产品:

查询:

select * from product_attributes 
where product_id in (812,813,814,815,816,817,818,819,820,1361,1362,1465,1466,1582,1583,1784,1794,1795,1802);

结果

# product_id, attribute_id, attribute_value_id
'812', '1', '12'
'812', '2', '13'
'812', '6', '139'
'813', '1', '12'
'813', '2', '13'
'813', '6', '249'
'814', '1', '12'
'814', '2', '13'
'814', '6', '268'
'815', '1', '12'
'815', '2', '13'
'815', '6', '249'
'816', '1', '12'
'816', '2', '13'
'816', '6', '249'
'817', '1', '12'
'817', '2', '13'
'817', '6', '268'
'818', '1', '12'
'818', '2', '13'
'818', '6', '249'
'819', '1', '12'
'819', '2', '277'
'819', '6', '310'
'820', '1', '12'
'820', '2', '13'
'820', '6', '93'
'1361', '1', '12'
'1361', '2', '36'
'1362', '1', '12'
'1465', '1', '12'
'1465', '2', '13'
'1465', '6', '249'
'1466', '1', '12'
'1466', '2', '13'
'1466', '6', '268'
'1582', '1', '12'
'1582', '2', '277'
'1582', '6', '139'
'1583', '1', '12'
'1583', '2', '277'
'1583', '6', '516'
'1784', '1', '12'
'1784', '2', '13'
'1784', '6', '139'
'1794', '1', '12'
'1794', '2', '13'
'1794', '6', '93'
'1802', '1', '12'
'1802', '2', '66'
'1802', '6', '93'

如果我应用了过滤器(1、12)和(6、268),则仅保留以下产品: 814、817、1466

我想要得到的结果:

ID为 812 的产品具有(1、12),(2、13),(6、139)组合;因为我要应用(1,12)和(6,268)的过滤组合,所以此产品具有n-1个过滤器组合,因此应将139作为新的可行选项添加到过滤器列表中。

这是我用来生成SQL的代码:

$wheres = [];

        foreach ($this->appliedFilters as $attributeId => $attributeValuesIds) {
            foreach ($attributeValuesIds as $attributeValueId) {
                $wheres[] = "attribute_id = {$attributeId} and attribute_value_id = {$attributeValueId}";
            }
        }

        $filteredSql = "SELECT * FROM product_attributes WHERE product_id IN (".implode(',', $this->filteredProductsIds).")";

        $filtersSql = 'SELECT * FROM product_attributes WHERE product_id IN (SELECT DISTINCT product_id FROM product_attributes';

        $firstWhere = array_shift($wheres);

        $filtersSql .= " WHERE ({$firstWhere})";

        foreach ($wheres as $where) {
            $filtersSql .= " OR ({$where})";
        }

        $filtersSql .= ')';

        $mergedSql = "
            SELECT A.attribute_value_id, A.attribute_id FROM ({$filteredSql}) as A
            INNER JOIN ({$filtersSql}) AS B ON B.product_id = A.product_id";
echo "$filteredSql
$filtersSql
$mergedSql";

输出的SQL是:

SELECT * FROM product_attributes WHERE product_id IN (812,813,814,815,816,817,818,819,820,1361,1362,1465,1466,1582,1583,1784,1794,1795,1802)
SELECT * FROM product_attributes WHERE product_id IN (SELECT DISTINCT product_id FROM product_attributes WHERE (attribute_id = 1 and attribute_value_id = 12) OR (attribute_id = 2 and attribute_value_id = 277))
SELECT A.attribute_value_id, A.attribute_id FROM (SELECT * FROM product_attributes WHERE product_id IN (812,813,814,815,816,817,818,819,820,1361,1362,1465,1466,1582,1583,1784,1794,1795,1802)) as A INNER JOIN (SELECT * FROM product_attributes WHERE product_id IN (SELECT DISTINCT product_id FROM product_attributes WHERE (attribute_id = 1 and attribute_value_id = 12) OR (attribute_id = 2 and attribute_value_id = 277))) AS B ON B.product_id = A.product_id

最终SQL的结果是:

'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'36', '2'
'36', '2'
'66', '2'
'66', '2'
'66', '2'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'310', '6'
'310', '6'
'310', '6'
'516', '6'
'516', '6'
'516', '6'

诸如23/249的值对于返回的产品是无效的值。我得到了我需要的额外价值,但我也得到了那些。

1 个答案:

答案 0 :(得分:0)

在示例查询中,您需要做的就是用子查询替换产品ID的列表。

SELECT *
FROM   product_attributes
WHERE  product_id IN
                      (
                      SELECT DISTINCT product_id
                      FROM            product_attributes
                      WHERE           (
                                                      attribute_id='a'
                                      AND             attribute_value_id='x')
                      OR             (
                                                      attribute_id='b'
                                      AND             attribute_value_id='y') ;