【问题标题】:Laravel MySQL apply product filters with eloquent (what is the correct query?)Laravel MySQL 用 eloquent 应用产品过滤器(正确的查询是什么?)
【发布时间】:2019-01-11 07:47:32
【问题描述】:

我正在尝试用 eloquent 过滤我的产品,但我的过滤器 where 语句永远不会像我目前的方式那样工作。

我的数据库表如下所示:

products

+---------------+
| id | name     |
+---------------+
| 1  | product1 | 
| 2  | product2 |
| 3  | product3 | 
| 4  | product4 |
+---------------+

properties

+------------------------------------+
| id | property_group_id | value(int)|
+------------------------------------|
| 1  | 1                 | 20        |
| 2  | 1                 | 10        |
| 3  | 2                 | 2         |
| 4  | 2                 | 4         |
+------------------------------------+

products_properties

+--------------------------+
| product_id | property_id | 
+--------------------------|
| 1          | 1           |
| 1          | 3           |
| 2          | 2           |
| 2          | 4           |
+--------------------------+

我目前使用 Eloquent 生成的 SQL 如下所示:

select * from `products` 
    where exists (
        select * from `properties`
            inner join `products_properties` 
                on `properties`.`id` = `products_properties`.`property_id` 
            where `products`.`id` = `products_properties`.`product_id` and 
            (
                `properties`.`property_group_id` = 1 and <--- property_group_id is not 
                `properties`.`value` >= 15 and                1 and 2 at the same time
                `properties`.`value` <= 25
            ) 
            and 
            (
                `properties`.`property_group_id` = 2 and
                `properties`.`value` >= 1 and 
                `properties`.`value` <= 2
            )
    )

我正在使用此查询查找product1,但这永远不会发生,因为property_group_id's 在同一行不匹配。在 2 个 where 语句之间使用 OR 也不起作用,因为只有其中 1 个语句必须为真才能找到某些东西。

Eloquent 中的 SQL 是这样生成的:

$products = Product::with(['properties' => function($query){
        $query->with('propertyGroup');
    }])
    ->whereHas('properties', function ($query) {
        // Use filter when filter params are passed
        if(array_key_exists('filterGroupIds', $this->filter) && count($this->filter['filterGroupIds']) > 0){

            // Loop through filters
            foreach($this->filter['filterGroupIds'] as $filter){
                // Add where for each filter
                $query->where(
                    [
                        ["properties.property_group_id", "=", $filter['id']], // 1 or 2
                        ["properties.value", ">=", $filter['min']], // 15 or 1
                        ["properties.value", "<=", $filter['max']]  // 1 or 2
                    ]
                );
            }
        }

    })
    ->get();

什么是正确的查询才能得到正确的结果?如果可能的话,我的 Eloquent 代码将如何生成此查询?

【问题讨论】:

  • 你到底想完成什么?
  • @lessan 产品过滤器。我正在使用我的查询查找 product1,但我当前的 where 语句永远不会起作用。
  • 是的,我明白了,但是您过滤的标准是什么?财产的价值?房产证?用英语而不是代码解释一下您要应用的过滤器是什么
  • @lessan 几乎基于properties 表中的值。用户为一个组选择 2 个值的范围,如果属性值介于此范围之间,则应找到该产品。目前只有 1 个过滤器可以正常工作,但是当我有多个过滤器时,我的查询将无法正常工作,如我上面的问题所示。

标签: php mysql laravel eloquent


【解决方案1】:

每个$filter 使用一个whereHas() 子句:

$products = Product::with('properties.propertyGroup');
if(array_key_exists('filterGroupIds', $this->filter) && count($this->filter['filterGroupIds']) > 0) {
    foreach($this->filter['filterGroupIds'] as $filter) {
        $products->whereHas('properties', function ($query) {
            $query->where([...]);
        });
    }
}

【讨论】:

    【解决方案2】:
    SELECT * FROM properties p 
    WHERE p.value BETWEEN minval AND maxval
    JOIN product_properties pp ON p.id = pp.property_id
    JOIN products pr ON pr.id = pp.product_id
    

    请注意,此查询根本没有优化,因为我不确切知道所需的数据和行为 此外,过滤是由属性 id 进行的,而不是由组 id 进行的,如果你想要按组只需更改

    p.id = pp.property_id
    

    p.property_group_id = pp.property_id
    

    对于雄辩的部分,尝试自己做并发布代码,但你需要先定义模型之间的关系

    【讨论】:

      猜你喜欢
      • 2021-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-23
      • 2014-09-25
      • 1970-01-01
      • 2021-07-14
      • 2021-08-22
      相关资源
      最近更新 更多