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

karchoker's avatar

How to join 4 tables to make 1 query

I'm noob in Laravel and i want some help with a Query. Here is my situation. I have 4 tables:

  • users (id, email, password.....)
  • user_profile (id, first_name, last_name,........, user_id)
  • companies (id, name,.......)
  • policies (id, policy_num, exp_date,........., user_id, company_id)

The table user have 5 users and every user have 10 policies. The table company have 3 companies.

$user_data=User::select('*')
                ->with('profile','policies')
                ->where('id', '=', $userId)
                ->first();

This code is working good, it retrieves the all the users and user_profile fields and all the policies(10) of this user with as you can see in this image, and i can show the user the details of the products on a home page.

http://i.stack.imgur.com/reMtF.png

I want to instead of appear the company_id from the policies table appears the name of the company from the company table. Any help is appreciated. Thanks in advance.

0 likes
23 replies
mstnorris's avatar

What is company related to?

You can eager load nested relationships like this:

$books = Book::with('author.contacts')->get();
1 like
karchoker's avatar

Hello mstnorris,

Here are my relationships:

User Model

public function profile()
    {
        return $this->hasOne('UserProfile');
    }

public function policies()
    {
        return $this->hasMany('Policy');
    }

Policy Model

public function company()
    {
        return $this->hasOne('Company');
    }
bobbybouwmann's avatar

You can do something like this I guess

$user = User::with('profile', 'policies.company')->where('id', '=', $userId)->get();

// Now you can access the company name like this
$user->policies->company->name
3 likes
bobbybouwmann's avatar

@mstnorris His question is quite clear... He already explained his models and the data he wants to receive from the database.

2 likes
karchoker's avatar

@mstnorris I already put the tags before my code.

@bobbybouwmann Thanks for your help, i tried what you tell me and i get this error:

$user_data=User::select('*')
            ->with('profile','policies', 'policies.company')
            ->where('users.id', '=', $userId)
            ->first();

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'companies.policy_id' in 'where clause' (SQL: select * from `companies` where `companies`.`policy_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10))

i think is something with my relationships

bobbybouwmann's avatar

Your with should look like this

->with('profile', 'policies.company')
1 like
karchoker's avatar

@bobbybouwmann Thanks for your help. I did the change but still have the same error.

$user_data=User::select('*')
            ->with('profile','policies.company')
            ->where('users.id', '=', $userId)
            ->first();

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'companies.policy_id' in 'where clause' (SQL: select * from `companies` where `companies`.`policy_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10))    

But in the companies table i dont have the policy_id field, the relation key is policies.company_id = companies.id

bobbybouwmann's avatar

Mmh I think you can't do it using Eloquent! You will need to do joins I guess

User::join('profile', 'profiles.user_id', '=', 'users.id')
    ->join('policies', 'policies.user_id', '=', 'users.id')
    ->join('companies', 'policies.company_id', '=', 'companies.id')
    ->where('users.id', '=', $userId)
    ->first();

Note: this is sample code, don't know for sure if this works but you get the idea ;)

1 like
karchoker's avatar

@bobbybouwmann Thanks for your help. I did this code before but the problem is that i'm getting 10 records with almost the same fields(client.id, client.email, client.first_name.......) only field that change is policy_num. With eloquent i get an Object (the user) and inside this object i get an 2 arrays(user_profile, policies). Check this picture http://i.stack.imgur.com/reMtF.png I wanted to inside the policies array i can get other array with the company fields.

jekinney's avatar

Do you have a policy_id field in your companies table?

1 like
shawnyv's avatar

This might be a bit of a stretch, but have you tried using belongsTo instead of "hasOne" in your Policy model, and including a company_id in your policy database table?

1 like
Kemito's avatar

Just a tip. It is not always the best thing to make 1 query. Sometimes 2 queries is 10 times better then 1 .

1 like
JarekTkaczyk's avatar

@shawnyv You definitely have relations wrong. The other side of hasOne/hasMany is always belongsTo, not hasOne.

I can't see what problem you had there apart from that.

1 like
depsimon's avatar

Hi, like others said you should use a belongsTo relationship.

You can also automatically load the company relation whenever you load a policy (so that you don't end up with something like this Model::with('relationA', 'relationB', 'relationB.relationC'). This is done with the $with property in your model.

<?php
class Policy extends Model
{

    $with = ['company']; // Automatically load these relations

    public function company()
    {
        return $this->belongsTo('Company'); // same as $this->belongsTo('Company', 'company_id', 'id');
    }
}

And then in your controller you would do something like this.

$user = User::with('profile', 'policies')->find($userId);
1 like
karchoker's avatar

Thank you very much to all for your answers, i will made the changes and post the results.

karchoker's avatar

@SimonD Thanks for your answer, do you know why im getting this error when i put this code on the model

$with = ['company'];

syntax error, unexpected '$with' (T_VARIABLE), expecting function (T_FUNCTION)

mehany's avatar

@SimonD your code is missing the accessibility attribute ( Public, private, protected ). @karchoker add that and it should work

2 likes

Please or to participate in this conversation.