【问题标题】:Eloquent wherein with join multiple tablesEloquent where with join 多个表
【发布时间】:2018-01-17 17:39:46
【问题描述】:

我有 4 个表格、项目、列表、catitem_item 和 item_listing。

items和listing是多对多的关系。 items 和 catitems 也是多对多的关系。

catitems 包含项目类别的列表。 列表就像物品所在的位置。 示例列表商店 A 可以有 item chair,并且 item chair 有多个 catitem 类别。

我的目标是获取类别列表下的项目,例如类别 1 AND 2 AND 3 ($cats) 以及该项目所在的列表信息。 因此,如果有 6 个椅子列表,它将返回 6 个椅子结果。

这是我目前的查询。

$items = DB::table('items')
                ->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
                ->join('item_listing', 'item_listing.item_id', '=', 'items.id')
                ->join('listings', 'item_listing.listing_id', '=', 'listings.id')
                ->whereIn('catitem_item.catitem_id', $cats)
                //->groupBy('items.id')
                //->having(DB::raw('count(*)'), '=', count($cats))
                ->select('items.id', 'items.name', 'items.price', 'items.slug', 'item_listing.listing_id', 'listings.name as listing_name', 'listings.slug as listing_slug')
                ->get();

【问题讨论】:

  • laravel 版本是什么?
  • 它的 laravel 5.3
  • 你能发一个sqlfiddle.com

标签: php mysql laravel eloquent laravel-eloquent


【解决方案1】:

请注意,您尝试执行此操作的方式可能会导致每个项目出现多行(每个相关列表一次)。更好的方法是为每个项目创建一个列表。

如果您使用 eloquent 模型并且正确设置了关系,您可以尝试以下操作:

$cats = [1, 2, 3];

$query = Item::with('listings');
foreach ($cats as $cat) {
    $query->whereHas('catitems', function($q) use($cat) {
        $q->where('id', $cat);
    });
}
$items = $query->get();

现在每个项目都应该有一个listings 属性。例如,对于第一项,您可以通过以下方式访问列表:

$item1 = $items[0];
$listings1 = $item1->listings;

注意whereHas() 可能会为$cats 数组中的每个条目创建一个相关的EXISTS 子查询。如果这很慢,您可以使用 JOIN 查询,例如:

$items = Item::with('listings')
    ->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
    ->whereIn('catitem_item.catitem_id', $cats)
    ->groupBy('items.id')
    ->having(DB::raw('count(*)'), '=', count($cats))
    ->select('items.*')
    ->get();

如果你不使用eloquent,你也可以自己做“eager loading”。

$items = DB::table('items')
    ->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
    ->whereIn('catitem_item.catitem_id', $cats)
    ->groupBy('items.id')
    ->having(DB::raw('count(*)'), '=', count($cats))
    ->select('items.*')
    ->get()
    ->keyBy('id');

foreach ($items as $item) {
    $item->listings = [];
}

$itemIds = $items->pluck('id');
$listings = DB::table('listings')
    ->join('item_listing', 'item_listing.listing_id', '=', 'listings.id')
    ->whereIn('item_listing.item_id', $itemIds)
    ->groupBy('listings.id')
    ->select('listings.*', DB::raw('group_concat(item_listing.item_id) as item_ids'))
    ->get();

foreach ($listings as $listing) {
    $itemIds = explode(',', $listing->item_ids);
    foreach ($itemIds as $itemId) {
        $items[$itemId]->listings[] = $listing;
    }
    $listing->forget('item_ids');
}

【讨论】:

  • 第一个解决方案有效,似乎雄辩的方式更简单。我仍在尝试第二种解决方案。你能检查一下吗,我在转换为雄辩的方式时遇到了一些问题stackoverflow.com/questions/45604577/…
猜你喜欢
  • 1970-01-01
  • 2015-05-01
  • 2020-07-09
  • 1970-01-01
  • 2015-02-02
  • 2014-06-13
  • 2021-09-08
  • 2018-06-04
  • 1970-01-01
相关资源
最近更新 更多