代码之家  ›  专栏  ›  技术社区  ›  Stefan

Laravel MySQL应用的产品过滤器很有说服力(正确的查询是什么?)

  •  0
  • Stefan  · 技术社区  · 7 年前

    我试图用雄辩的口才过滤我的产品,但我的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           |
    +--------------------------+
    

    我正在生成的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 不匹配同一行。在两个where语句之间使用OR也不起作用,因为只有其中一个必须为true才能找到某些内容。

    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();
    

    为了得到正确的结果,正确的查询是什么?如果可能的话,我的雄辩的代码将如何生成这个查询?

    2 回复  |  直到 7 年前
        1
  •  1
  •   Jonas Staudenmeir    7 年前

    使用一个 whereHas() 条款依据 $filter :

    $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
  •  1
  •   lessan    7 年前
    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
    

    对于雄辩的部分,试着独立完成并发布代码,您需要首先定义模型之间的关系