Laravel Eloquent 在与其他表连接后从关系中选择字段
Posted
技术标签:
【中文标题】Laravel Eloquent 在与其他表连接后从关系中选择字段【英文标题】:Laravel Eloquent selecting field from relationship after joining with other tables 【发布时间】:2021-12-21 03:19:23 【问题描述】:我有一个查询,我已将多个表连接在一起,并且由于它们具有相同名称的字段,因此我使用 select 查询仅挑选出我需要的字段。但是,我还需要包含从 with 查询获得的结果,但我不知道如何在 select 查询中指定它。
$display_tickets = ManualTicket::select('u.name as name', 'i.name as initiator', 'manual_tickets.status as status', 'manual_tickets.description as description', 'manual_tickets.location as location', 'manual_tickets.created_at as created_at', 'manual_tickets.initiator_id as initiator_id', 'manual_tickets.id as manual_ticket_id','manual_tickets.manual_ticket_log as manual_ticket_log_id')
->leftJoin('users as u', 'u.id', '=', 'manual_tickets.user_id')
->leftJoin('users as i', 'i.id', '=', 'manual_tickets.initiator_id')
->where(function ($checkClients) use($target_client_id)
$checkClients->where('u.client_id', '=', $target_client_id)
->orWhere('i.client_id', '=', $target_client_id);
)
->whereBetween('manual_tickets.created_at', [$start_date->toDateString(), $end_date->addDays(1)->toDateString()])
->with('manual_ticket_log')
->orderBy("created_at", "DESC")->get();
我试图通过使用下面的代码来包含手动工单日志,但它说手动工单表中没有这样的字段。
'manual_tickets.manual_ticket_log as manual_ticket_log_id')
简而言之,如何将 ->with('manual_ticket_log') 中的 with 关系的结果包含到 select 语句中
--EDIT-- (尝试用查询替换联接)
但是,我的 SQL 查询似乎有任何错误,我认为这源于导致显示此错误的代码的 whereHas 部分。
strtolower() 期望参数 1 是字符串,给定对象
$display_tickets = ManualTicket::select('*')
->with('user')
->with('initiator')
->with('manual_ticket_log')
->where(function ($checkClients) use($target_client_id)
$checkClients->whereHas('user', function ($checkClient) use($target_client_id)
$checkClient->where('client_id', '=', $target_client_id);
)
->orWhere($checkClients->whereHas('initiator', function ($checkClient2) use($target_client_id)
$checkClient2->where('client_id', '=', $target_client_id);
));
)
->whereBetween('manual_tickets.created_at', [$start_date->toDateString(), $end_date->addDays(1)->toDateString()])
->orderBy("created_at", "DESC")->get();
【问题讨论】:
你不能也不应该。雄辩的关系在单独的查询中加载,有充分的理由不使用连接,而是对您的用户关系也这样做 @apokryfos 我尝试用 with 替换连接查询,但我的操作似乎有错误。你能告诉我我做错了什么吗 尝试用->orWhereHas
替换 orWhere($checkClients->whereHas
@apokryfos 谢谢,我相信我的问题已经解决了。您可能想发布您的 cmets 作为答案,以便我将其标记为正确
【参考方案1】:
您应该加入该表以获取字段形式:
$display_tickets = ManualTicket::select('u.name as name', 'i.name as initiator', 'manual_tickets.status as status', 'manual_tickets.description as description', 'manual_tickets.location as location', 'manual_tickets.created_at as created_at', 'manual_tickets.initiator_id as initiator_id', 'manual_tickets.id as manual_ticket_id','manual_tickets.manual_ticket_log as manual_ticket_log_id',
'manual_tickets.manual_ticket_log as manual_ticket_log_id')
->leftJoin('users as u', 'u.id', '=', 'manual_tickets.user_id')
->leftJoin('users as i', 'i.id', '=', 'manual_tickets.initiator_id')
->leftJoin('manual_ticket_logs',function ($join)
$join->on('manual_ticket_logs.manual_ticket_id', '=', 'manual_tickets.id')
->on('manual_ticket_logs.id', '=', \DB::raw("(select max(id) from manual_ticket_logs WHERE manual_ticket_logs.manual_ticket_id = manual_tickets.id)"));
)
->where(function ($checkClients) use($target_client_id)
$checkClients->where('u.client_id', '=', $target_client_id)
->orWhere('i.client_id', '=', $target_client_id);
)
->whereBetween('manual_tickets.created_at', [$start_date->toDateString(), $end_date->addDays(1)->toDateString()])
->with('manual_ticket_log')
->orderBy("created_at", "DESC")->get();
请确保最新加入子句中的字段名称。
【讨论】:
有没有办法让它保持原样? 问题是:在 Laravel 中使用单独的查询获取信息,据我所知,没有其他直接的方法。 在这种情况下,如果我要使用加入,我只希望手动工单与手动工单日志中的最新条目一起加入(因为一张特定的手动工单可能有很多日志)如何能做到吗? 我已经更新了加入最新行的代码,更多关于加入最新行的信息:***.com/a/45570994/10573560【参考方案2】:你可以试试这个
$display_tickets = ManualTicket::select('u.name as name', 'i.name as initiator', 'manual_tickets.status as status', 'manual_tickets.description as description', 'manual_tickets.location as location', 'manual_tickets.created_at as created_at', 'manual_tickets.initiator_id as initiator_id', 'manual_tickets.id as manual_ticket_id','manual_tickets.manual_ticket_log as manual_ticket_log_id')
->leftJoin('users as u', 'u.id', '=', 'manual_tickets.user_id')
->leftJoin('users as i', 'i.id', '=', 'manual_tickets.initiator_id')
->where(function ($checkClients) use($target_client_id)
$checkClients->where('u.client_id', '=', $target_client_id)
->orWhere('i.client_id', '=', $target_client_id);
)
->whereBetween('manual_tickets.created_at', [$start_date->toDateString(), $end_date->addDays(1)->toDateString()])
->with(['manual_ticket_log' => function($query)
$query->select('field1', 'field2');
])
->orderBy("created_at", "DESC")->get();
或者这样做
->with('manual_ticket_log:field1, field2')
【讨论】:
我试过但同样的错误,手动票证中找不到手动票证日志列【参考方案3】:您可以利用 Laravel 关系使代码更具可读性并避免昂贵的leftJoin
:
$display_tickets = ManualTicket::select('*')
->with([ 'user', 'initiator', 'manual_ticket_log' ])
->where(function ($checkClients) use($target_client_id)
$checkClients->whereHas('user', function ($checkClient) use($target_client_id)
$checkClient->where('client_id', '=', $target_client_id);
)->orWhereHas('initiator', function ($checkClient2) use($target_client_id)
$checkClient2->where('client_id', '=', $target_client_id);
));
)->whereBetween('created_at', [$start_date->toDateString(), $end_date->addDays(1)->toDateString()])
->orderBy("created_at", "DESC")
->get();
【讨论】:
以上是关于Laravel Eloquent 在与其他表连接后从关系中选择字段的主要内容,如果未能解决你的问题,请参考以下文章