【问题标题】:Laravel query builder returning more rows than it shouldLaravel 查询生成器返回的行数超出预期
【发布时间】:2019-12-17 19:23:36
【问题描述】:

具有如下表结构:

 properties
 ------------
 id
 property_name

 buildings
 -------------
 id
 building_name
 property_id

 floors
 -------------
 id
 floor_coode
 building_id

 units
 -------------
 id
 unit_number
 floor_id

 amenities
 ------------
 id
 amenity_name
 amenity_value
 unit_id

 categories
 -----------
 id
 category_name
 parent_id

amenity_categories
 ------------
amenity_id
category_id


现在,我尝试运行以下查询:

        $query = \DB::table('amenities')
            ->join('units', 'units.id', 'amenities.unit_id')
            ->join('floors', 'floors.id', 'units.floor_id')
            ->join('buildings', 'buildings.id', 'floors.building_id')
            ->join('properties', 'properties.id', 'buildings.property_id')
            ->leftjoin('amenity_category', 'amenities.id', 'amenity_category.amenity_id')
            ->leftjoin('categories', 'categories.id', 'amenity_category.category_id')
            ->select('amenities.id as ame_id', 'amenities.amenity_name', 'amenities.amenity_value','units.id as unit_id', 'units.unit_number','amenity_category.*','categories.parent_id as cat_parent_id')
            ->where('buildings.id',$building_id)
            ->orderBy('units.unit_number','asc');

        $data = $query->get();

有了这个,它返回的行比它应该的多,例如让我们看看一个特定单元的块:107

[300] => stdClass Object
                (
                    [ame_id] => 2
                    [amenity_name] => CU
                    [amenity_value] => 20
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 2
                    [category_id] => 8
                    [cat_parent_id] => 5
                )

            [301] => stdClass Object
                (
                    [ame_id] => 3
                    [amenity_name] => VR
                    [amenity_value] => 50
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 
                    [category_id] => 
                    [cat_parent_id] => 
                )

            [302] => stdClass Object
                (
                    [ame_id] => 4
                    [amenity_name] => SF
                    [amenity_value] => 320
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 4
                    [category_id] => 6
                    [cat_parent_id] => 5
                )

            [303] => stdClass Object
                (
                    [ame_id] => 1
                    [amenity_name] => BO
                    [amenity_value] => 20
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 1
                    [category_id] => 6
                    [cat_parent_id] => 5
                )

            [304] => stdClass Object
                (
                    [ame_id] => 4
                    [amenity_name] => SF
                    [amenity_value] => 320
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 4
                    [category_id] => 9
                    [cat_parent_id] => 5
                )

            [305] => stdClass Object
                (
                    [ame_id] => 1
                    [amenity_name] => BO
                    [amenity_value] => 20
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 1
                    [category_id] => 8
                    [cat_parent_id] => 5
                )

            [306] => stdClass Object
                (
                    [ame_id] => 4
                    [amenity_name] => SF
                    [amenity_value] => 320
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 4
                    [category_id] => 10
                    [cat_parent_id] => 5
                )

            [307] => stdClass Object
                (
                    [ame_id] => 1
                    [amenity_name] => BO
                    [amenity_value] => 20
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 1
                    [category_id] => 9
                    [cat_parent_id] => 5
                )

            [308] => stdClass Object
                (
                    [ame_id] => 4
                    [amenity_name] => SF
                    [amenity_value] => 320
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 4
                    [category_id] => 11
                    [cat_parent_id] => 5
                )

            [309] => stdClass Object
                (
                    [ame_id] => 1
                    [amenity_name] => BO
                    [amenity_value] => 20
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 1
                    [category_id] => 10
                    [cat_parent_id] => 5
                )

            [310] => stdClass Object
                (
                    [ame_id] => 2
                    [amenity_name] => CU
                    [amenity_value] => 20
                    [unit_id] => 1
                    [unit_number] => 107
                    [amenity_id] => 2
                    [category_id] => 6
                    [cat_parent_id] => 5
                )

在这里,您可以看到实际上只有 4 个不同的ame_id,范围从 1 到 4,以及它应该如何返回。我在哪里做错了?此外,删除该数据透视表不是我的想法,因为我还需要加载该关系数据。

【问题讨论】:

    标签: mysql laravel laravel-query-builder


    【解决方案1】:

    您还可以使用 groupby 来获取唯一的行

    $query = \DB::table('amenities')
        ->join('units', 'units.id', 'amenities.unit_id')
        ->join('floors', 'floors.id', 'units.floor_id')
        ->join('buildings', 'buildings.id', 'floors.building_id')
        ->join('properties', 'properties.id', 'buildings.property_id')
        ->leftjoin('amenity_category', 'amenities.id', 'amenity_category.amenity_id')
        ->leftjoin('categories', 'categories.id', 'amenity_category.category_id')
        ->select('amenities.id as ame_id', 'amenities.amenity_name', 'amenities.amenity_value','units.id as unit_id', 'units.unit_number','amenity_category.*','categories.parent_id as cat_parent_id')
        ->where('buildings.id',$building_id)
        ->orderBy('units.unit_number','asc')
        ->groupby('amenities.id');
    
    $data = $query->get();
    

    【讨论】:

    • 语法错误或访问冲突:1055 SELECT 列表的表达式 #7 不在 GROUP BY 子句中,并且包含非聚合列“amenity_db.amenity_category.category_id”,它在功能上不依赖于 GROUP BY 子句中的列;这与 sql_mode=only_full_group_by 不兼容
    • 将通过这个命令改变MySQL中的sql模式来简单解决,SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));使用 set 语句时,此更改仅适用于运行时。当您的服务器重新启动时,您的更改将被覆盖。您可以在 my.ini 中进行更改并重新启动服务器以永久更改 mysql 配置
    • 我不认为这是迄今为止最好的做法。
    【解决方案2】:

    这是数据库的正确行为和雄辩。否则,您必须省略列,这会导致 category_id 等重复项。或者您必须使用子查询,在其中预先选择您想要的唯一类别。

    你不能处理雄辩的关系和急切的加载吗? 然后获得所有便利设施,例如:

    $amenities = Amenity::all()->with('units.floors');
    

    以及使用它们时

    foreach($amenities as $amenity){
        units = $amenity->unit();
    }
    

    代码未测试

    更新 您可以像这样使用查询构建器创建子查询(示例不是通用表)

    $subQuery = DB::table('firsttable')->where('id', 77);
    

    然后在其他查询中使用它,如下所示:

    return DB::table(DB::raw("({$subQuery->toSql()}) as sub"))
               ->leftJoin('secondtable','id', '=', 'secondtable_id')
               ->mergeBindings($subQuery)
               ->get();
    

    希望这有助于为您指明正确的方向?

    【讨论】:

    • 我明白,但是,我经历了很多,雄辩对于更大的任务来说相当慢。您能否建议使用查询生成器的类似方法,例如在第一次查询时不使用该数据透视表,然后以一种有效的方式使用舒适值调用它。
    • 您能推荐子查询技术吗?
    猜你喜欢
    • 2016-12-17
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    • 2015-03-26
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多