Laravel根据输入选择列和连接表格

huangapple go评论56阅读模式
英文:

Laravel select column and join table based on input

问题

以下是您的翻译:

我有一个类似这样的查询:

```php
$query = Merchant::select(
    'merchants.*',
    'users.name as rm_name',
    'users.employee_id as rm_emp_id',
    'stU.name as status_updated_by_name',
    'rUsers.name as team_lead',
    'tmU.name as territory_manager',
    'amU.name as area_manager',
    'rmU.name as regional_manager',
    'districts.name as district_name',
    'areas.name as area_name',
    'producers.name as producer_name',
    'markets.market_name',
    'markets.code as market_code',
    'categories.name as category_name',
    'divisions.name as division_name',
    'thanas.name as thana_name',
    'merchants.merchant_uid as merchant_uid'
)
    ->join('users', 'users.id', '=', 'merchants.rm_id')
    ->join('users as rUsers', 'rUsers.id', '=', 'users.reporting_to')
    ->leftJoin('users as tmU', 'tmU.id', '=', 'rUsers.reporting_to')
    ->leftJoin('users as amU', 'amU.id', '=', 'tmU.reporting_to')
    ->leftJoin('users as rmU', 'rmU.id', '=', 'amU.reporting_to')
    ->leftJoin('users as stU', 'stU.id', '=', 'merchants.status_updated_by')
    ->leftJoin('markets', 'markets.id', '=', 'merchants.market_id')
    ->leftJoin('categories', 'categories.id', '=', 'merchants.category_id')
    ->leftJoin('producers', 'producers.id', '=', 'merchants.producer_id')
    ->leftjoin('divisions', 'divisions.id', '=', 'merchants.division_id')
    ->leftjoin('districts', 'districts.id', '=', 'merchants.district_id')
    ->leftjoin('thanas', 'thanas.id', '=', 'merchants.thana_id')
    ->leftjoin('new_areas as areas', 'areas.id', '=', 'merchants.area_id')
    ->get();

在这里,用户可以通过 UI 选择一个 district,也可以将其保留为未选择状态。

我通过 $request 获取用户输入(尚未使用)。我可以通过 $request->district_id 获取一个地区(district)。

如果选择了 district,我想选择 districts.name as district_name 并与 districts 表进行连接。

否则,每次连接到地区都是不必要的。实际上,对于其他列也是如此。

我应该如何实现这一点?

英文:

I have a query like this:

$query = Merchant::select(
    'merchants.*',
    'users.name as rm_name',
    'users.employee_id as rm_emp_id',
    'stU.name as status_updated_by_name',
    'rUsers.name as team_lead',
    'tmU.name as territory_manager',
    'amU.name as area_manager',
    'rmU.name as regional_manager',
    'districts.name as district_name',
    'areas.name as area_name',
    'producers.name as producer_name',
    'markets.market_name',
    'markets.code as market_code',
    'categories.name as category_name',
    'divisions.name as division_name',
    'thanas.name as thana_name',
    'merchants.merchant_uid as merchant_uid'
)
    ->join('users', 'users.id', '=', 'merchants.rm_id')
    ->join('users as rUsers', 'rUsers.id', '=', 'users.reporting_to')
    ->leftJoin('users as tmU', 'tmU.id', '=', 'rUsers.reporting_to')
    ->leftJoin('users as amU', 'amU.id', '=', 'tmU.reporting_to')
    ->leftJoin('users as rmU', 'rmU.id', '=', 'amU.reporting_to')
    ->leftJoin('users as stU', 'stU.id', '=', 'merchants.status_updated_by')
    ->leftJoin('markets', 'markets.id', '=', 'merchants.market_id')
    ->leftJoin('categories', 'categories.id', '=', 'merchants.category_id')
    ->leftJoin('producers', 'producers.id', '=', 'merchants.producer_id')
    ->leftjoin('divisions', 'divisions.id', '=', 'merchants.division_id')
    ->leftjoin('districts', 'districts.id', '=', 'merchants.district_id')
    ->leftjoin('thanas', 'thanas.id', '=', 'merchants.thana_id')
    ->leftjoin('new_areas as areas', 'areas.id', '=', 'merchants.area_id')
    ->get();

Here, a user can select a district or can leave it as unselected from the UI.

I get a user input via $request (I have not used it yet). I can fetch a district by $request->district_id.

I want to select districts.name as district_name and join with districts table only if district is selected.

Otherwise, it will be unnecessary to join with district each time. In fact, it is true for other columns also.

How can I achieve this?

答案1

得分: 1

Sure, here is the translated part:

所以,您想要使用的是->when(),它允许您在表达式为true时将某些内容添加到查询中。它就像一个if语句,但不会在代码中“打断”,而是允许您在同一个调用中链接它(非常有用)。

$query = Merchant::select(
    'merchants.*',
    'users.name as rm_name',
    'users.employee_id as rm_emp_id',
    'stU.name as status_updated_by_name',
    'rUsers.name as team_lead',
    'tmU.name as territory_manager',
    'amU.name as area_manager',
    'rmU.name as regional_manager',
    'areas.name as area_name',
    'producers.name as producer_name',
    'markets.market_name',
    'markets.code as market_code',
    'categories.name as category_name',
    'divisions.name as division_name',
    'thanas.name as thana_name',
    'merchants.merchant_uid as merchant_uid'
)
    ->join('users', 'users.id', '=', 'merchants.rm_id')
    ->join('users as rUsers', 'rUsers.id', '=', 'users.reporting_to')
    ->leftJoin('users as tmU', 'tmU.id', '=', 'rUsers.reporting_to')
    ->leftJoin('users as amU', 'amU.id', '=', 'tmU.reporting_to')
    ->leftJoin('users as rmU', 'rmU.id', '=', 'amU.reporting_to')
    ->leftJoin('users as stU', 'stU.id', '=', 'merchants.status_updated_by')
    ->leftJoin('markets', 'markets.id', '=', 'merchants.market_id')
    ->leftJoin('categories', 'categories.id', '=', 'merchants.category_id')
    ->leftJoin('producers', 'producers.id', '=', 'merchants.producer_id')
    ->leftjoin('divisions', 'divisions.id', '=', 'merchants.division_id')
    ->leftjoin('thanas', 'thanas.id', '=', 'merchants.thana_id')
    ->leftjoin('new_areas as areas', 'areas.id', '=', 'merchants.area_id')
    ->when($request->district_id, function (Builder $query, int $id) {
        return $query->addSelect('districts.name as district_name')
            ->leftjoin('districts', 'districts.id', '=', 'merchants.district_id')
            ->where('districts.id', $id); // I am assuming you want to filter by ID, else remove this where
    })
    ->get();

I hope this helps! If you have any more questions or need further assistance, feel free to ask.

英文:

So, what you want to use is ->when(), it allows you to add something to the query if an expression is true. It is exactly an if, but instead of "breaking" your code in parts, it just allows you to chain it in the same call (very useful).

$query = Merchant::select(
    'merchants.*',
    'users.name as rm_name',
    'users.employee_id as rm_emp_id',
    'stU.name as status_updated_by_name',
    'rUsers.name as team_lead',
    'tmU.name as territory_manager',
    'amU.name as area_manager',
    'rmU.name as regional_manager',
    'areas.name as area_name',
    'producers.name as producer_name',
    'markets.market_name',
    'markets.code as market_code',
    'categories.name as category_name',
    'divisions.name as division_name',
    'thanas.name as thana_name',
    'merchants.merchant_uid as merchant_uid'
)
    ->join('users', 'users.id', '=', 'merchants.rm_id')
    ->join('users as rUsers', 'rUsers.id', '=', 'users.reporting_to')
    ->leftJoin('users as tmU', 'tmU.id', '=', 'rUsers.reporting_to')
    ->leftJoin('users as amU', 'amU.id', '=', 'tmU.reporting_to')
    ->leftJoin('users as rmU', 'rmU.id', '=', 'amU.reporting_to')
    ->leftJoin('users as stU', 'stU.id', '=', 'merchants.status_updated_by')
    ->leftJoin('markets', 'markets.id', '=', 'merchants.market_id')
    ->leftJoin('categories', 'categories.id', '=', 'merchants.category_id')
    ->leftJoin('producers', 'producers.id', '=', 'merchants.producer_id')
    ->leftjoin('divisions', 'divisions.id', '=', 'merchants.division_id')
    ->leftjoin('thanas', 'thanas.id', '=', 'merchants.thana_id')
    ->leftjoin('new_areas as areas', 'areas.id', '=', 'merchants.area_id')
    ->when($request->district_id, function (Builder $query, int $id) {
        return $query->addSelect('districts.name as district_name')
            ->leftjoin('districts', 'districts.id', '=', 'merchants.district_id')
            ->where('districts.id', $id); // I am assuming you want to filter by ID, else remove this where
    })
    ->get();

See that I have introduced ->when (the position does not matter, only that it is added before you execute the query). It will require the first parameter to be an expression that can be interpreted as boolean, if district_id is null because there is no selection, then it is evaluated as false so nothing else happens (the function is not executed).

If district_id has any content that is not falsy (a string or integer that is not 0 or false) it will be evaluated as true and the function (second parameter) will be executed, in our case adding an extra select (because I have removed it from the main select as you said, due to not having the join), adding the join, and I also added a filter (where) so you filter by the $request->district_id = $id, feel free to remove that one or leave it as it is.


Super personal recommendation: It is not usual to end up with a huge query and custom query like yours. Depending on your case (that you did not mention at all), I do think your query is hyper overengineered. I would recommend to use relationships, else you are literally making the relationships on this part of the code and if any of them changes later, you have to edit this, if it was a literal eager loaded relationship, then nothing should change. So, this is not exactly the larave way, it is not standard, I would try to avoid it unless you have a very good and exceptional case.

huangapple
  • 本文由 发表于 2023年5月14日 23:32:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76248292.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定