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

theUnforgiven's avatar

Eloquent, relationships and foreach loops

I have the following html table:

Which I want to populate with the income and any expenditure. I have a payments table and a rents table, these will be income and expenditure respectively.

I have the following query, which is producing the correct amount of results, but I don't really want to do 3 foreach loops

$incomes = Company::with(['rents' => function($q) {
                                $q->where('status', '!=', 'unpaid');
                            }])
                            ->with('payments')
                            ->where('id', user()->companies()->first()->id)
                            ->get();

Rents Table:

Payments Table:

How the collection is rendering when dd()

Again like I say I wan this to fit within the html table is laid out so it all fits in the correct places, but don't see how without doing 3 foreach loops.

Any help/advice greatly appreciated.

0 likes
14 replies
tykus's avatar

You should be able to use joins instead, something like:

DB::table('companies')
    ->where('companies.id', user()->companies()->first()->id)
    ->leftJoin('payments', 'companies.id', '=', 'payments.landlord_id')
    ->leftJoin('rents', function ($join) {
        $join->on('companies.id', '=', 'rents.company_id')->where('status', '!=', 'unpaid')
    })->get();

You would need to probably alias columns to line up column names from rents with and payments tables, but otherwise it will work.

Have a look at the Sub joins part of https://laravel.com/docs/5.8/queries#joins to see how you might select the specific columns from the joined tables - you could selectRaw() to alias the columns that need aliasing

1 like
theUnforgiven's avatar

That query is showing:

SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous (SQL: select * from `companies` left join `payments` on `companies`.`id` = `payments`.`landlord_id` left join `rents` on `companies`.`id` = `rents`.`company_id` and `status` != unpaid where `id` = 59)
tykus's avatar

Updated above:

//
->where('companies.id', user()->companies()->first()->id)
//
tykus's avatar

No worries!

That query is simply an example jumping off point for you; I expect you will need the subJoin approach to alias your payments.amount differently to the rent.amount since they map to income and expenditure columns on your HTML table.

theUnforgiven's avatar

Yeah, I can see that now and I think I should be able to figure the rest out, thanks buddy. Failing that I may be back later :)

theUnforgiven's avatar

There's 8 records showing and they are duplicates of each rent item, so each showing twice, there should be 6 items in total (should be 7 but we exclude the unpaid one) I guess i need a groupBy() of some sort just not sure as I'm a little new to this join/sub query stuff.

theUnforgiven's avatar

Also this is kinda like a Balance sheet, so income should be rents and payments will be expenditure

tykus's avatar

Can you show us you current Eloquent/Query Builder query?

theUnforgiven's avatar
$incomes = DB::table('companies')
                        ->where('companies.id', user()->companies()->first()->id)
                        ->leftJoin('payments', 'companies.id', '=', 'payments.company_id')
                        ->leftJoin('rents', function ($join) {
                            $join->on('companies.id', '=', 'rents.landlord_id')->where('status', '!=', 'unpaid');
                        })
                        ->leftJoin('properties', 'rents.property_id', '=', 'properties.id')
                        ->get();
tykus's avatar

Are you wanting to aggregate all income and expenditure for a property/landlord on a single row?

theUnforgiven's avatar

Sorry, I'm wanting to show all income/rents that are paid so there should be 5 rows there, then for expenditure/payments, there's 2 rows so in total on the html table/view I should see 7 rows.

theUnforgiven's avatar

@tykus - presuming you saw my reply, I'm still looking to get this sorted with a solution of sort, your help greatly appreciated.

Please or to participate in this conversation.