Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

requincreative's avatar

Newbie Pivot Table Confusion

Greetings,

I am refactoring a process to use pivot tables to keep my models clean and make life simpler for reporting and, so far, most everything is good. I am, however, having an issue with trying to use the pivot tables in a closure query.

I have two models:

class ThreatRisk extends Model
{

 public function actions()
    {
        return $this->belongsToMany('App\ThreatRiskDataAction')->withPivot('name', 'date')->withTimestamps();
    }
}
class ThreatRiskDataAction extends Model
{
   
    public function threats()
    {
        return $this->belongsToMany('App\ThreatRisk')->withTimestamps();
    }
}

Here is my pivot migration. As you can see I am passing additional columns with the pivot for ease of use.

Schema::create('threat_risk_threat_risk_data_action', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('threat_risk_id');
            $table->unsignedBigInteger('threat_risk_data_action_id');
            $table->text('name');
            $table->text('date');
            $table->timestamps();
        });


Here is the data table for the data actions

ThreatRiskDataAction Table

id	name	created_at	updated_at
1	Informed Student of Infraction	2020-11-18 08:35:50.247	2020-11-18 08:35:50.247
2	Bullying Investigation	2020-11-18 08:36:02.840	2020-11-18 08:36:02.840
3	Notified Student's Parents	2020-11-18 08:36:31.677	2020-11-18 08:36:31.677
4	Contacted Police	2020-11-18 08:36:49.327	2020-11-18 08:36:49.327
5	Notified Special Education	2020-11-18 08:37:01.177	2020-11-18 08:37:01.177
6	Person(s) Notified	2020-11-18 08:37:12.717	2020-11-18 08:37:12.717
7	Notified Victim(s) & Their Parents	2020-11-18 08:37:28.377	2020-11-18 08:37:28.377

I am trying to return all records that use the data action of Contacted Police. I have the following, which works, but I have a feeling that I should not have to pass in the threat_risk_data_action_id into the query. It seems like I should be able to use the name of the data action instead of the id :

$case5 = ThreatRisk::whereBetween('report_date', [$start, $end])
            ->where(function ($query) {
                $query->whereHas('actions', function ($query){
                    $query->where('threat_risk_data_action_id', 4);
                });
             
            })
            ->count();

Thanks for your assistance and grace.

0 likes
12 replies
automica's avatar

@requincreative you should be able to query using name from ThreatRiskDataAction table

$case5 = ThreatRisk::whereBetween('report_date', [$start, $end])
            ->where(function ($query) {
                $query->whereHas('actions', function ($query){
                    $query->where('name', 'Contacted Police')
                });
            })
            ->count();

if you want to query the two pivot columns on your join table you can use

->wherePivot()

https://laravel.com/docs/8.x/eloquent-relationships#filtering-relationships-via-intermediate-table-columns

requincreative's avatar

Thank you.

I tried that and I got the following error:

Ambiguous column name 'name'.

I believe this is because I already have a "name" column on the pivot table and I am using the column "name" in the DataActions table.

automica's avatar

@requincreative you can do

 $query->where('actions.name', 'Contacted Police')

it might also help to remove compound names. Can ThreatRisk be Risk and ThreatAction be Action?

requincreative's avatar

Thank you, I tried that as well and got this error:

The multi-part identifier "actions.name" could not be bound.

I am running on SQL Server if that helps

requincreative's avatar

Normally I would avoid the compound naming in a standalone project, but this is a small-scale enterprise application with different Risk Models and Tables.

automica's avatar
automica
Best Answer
Level 54

@requincreative I'm not familiar with SQL Server or if this is an issue with the query or something specific to the server.

$action = 'Contacted Police';

$actionId = ThreatRiskDataAction::whereName($action)->first()->pluck('id');

$case5 = ThreatRisk::whereBetween('report_date', [$start, $end])
            ->where(function ($query) use ($actionId) {
                $query->whereHas('actions', function ($query) use($actionId){
                    $query->where('threat_risk_data_action_id', $actionId);
                });
             
            })
            ->count();

This will get you what you want, until @michaloravec reads this thread :P

1 like
requincreative's avatar

Thank you for your assistance.

I was able to get it to work by injecting the table name into the column identifier. I suppose that is the price of admission when I have so little experience in setting up a DB for a project like this.

ThreatRisk::whereBetween('report_date', [$start, $end])
            ->where(function ($query) {
                $query->whereHas('actions', function ($query){
       $query->where('Threat_Risk_Data_Actions.name', 'Contacted Police');
       });
                $query->orWhere('other_immediate_actions', 'like', '%police%');
            })
            ->count();
Sinnbeck's avatar

@automica You can pluck on the query :)

$actionId = ThreatRiskDataAction::whereName($action)->pluck('id');
2 likes
automica's avatar

sorry to hear that. I hope you are feeling better now from your covids.

Please or to participate in this conversation.