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

Macka's avatar
Level 1

Multiple joins with unexpected results

I'm trying to generate a report that requires the joining of two tables. My database structure is such that:

  • A transaction has transaction date and an item.
  • An item has one of many prices.
  • Prices have a valid_from and valid_to date.

Transaction table:

Schema::create('transactions', function (Blueprint $table) {
            $table->id();
            $table->foreignId('item_id')->constrained();
            $table->integer('qty')->nullable();
            $table->timestamp('issue_date')->default(DB::raw('CURRENT_TIMESTAMP'));
});

Item table:

Schema::create('items', function (Blueprint $table) {
            $table->id();
            $table->string('barcode',20);
            $table->string('description',100);
});

Prices table:

Schema::create('prices', function (Blueprint $table) {
            $table->id();
            $table->foreignId('item_id')->constrained();
            $table->decimal('price',9,3);
            $table->date('valid_from')->default(DB::raw('CURRENT_TIMESTAMP'));
            $table->date('valid_to')->default('9999-12-31');
            $table->unique(['item', 'valid_from']);
});

If I run the following query in phpMyAdmin I get the expected result:

SELECT `transactions`.*, `prices`.`price`, `prices`.`valid_from`, `prices`.`valid_to` FROM `transactions`
left JOIN `prices` ON `transactions`.`item_id` = `prices`.item_id
    WHERE `transactions`.`qty` is not null AND `transactions`.`issue_date` >= `prices`.`valid_from` AND `transactions`.`issue_date` <= `prices`.`valid_to`
    ORDER By `transactions`.`id`

When I try to build the equivalent using laravel, I get a null result:

$items = Transaction::where('transactions.qty','!=',null)
                    ->leftjoin('prices', function ($join) {
                        $join->on('transactions.item_id', '=', 'prices.item_id');
                    })
                    ->where('prices.valid_from', '<=', 'transactions.issue_date')
                    ->where('prices.valid_to', '>=', 'transactions.issue_date');
                    ->paginate(25);

If I try to structure it like so, I get results, but the only fields with data are the transaction fields, all other fields are present but null:

$items = Transaction::where('transactions.qty','!=',null)
                    ->leftjoin('prices', function ($join) {
                        $join->on('transactions.item_id', '=', 'prices.item_id')
                                   ->where('prices.valid_from', '<=', 'transactions.issue_date')
                                   ->where('prices.valid_to', '>=', 'transactions.issue_date');
                    })
                    ->paginate(25);

Output:

{
  "data": [
    {
      "id": null,
      "item_id": null,
      "qty": 5,
      "issue_date": "2023-01-22 15:45:09",
      "price": null,
      "valid_from": null,
      "valid_to": null
    },
    {
      "id": null,
      "item_id": null,
      "qty": 4,
      "issue_date": "2023-01-22 21:18:59",
      "price": null,
      "valid_from": null,
      "valid_to": null
    },
    {
      "id": null,
      "item_id": null,
      "qty": 2,
      "issue_date": "2023-01-29 20:32:42",
      "price": null,
      "valid_from": null,
      "valid_to": null
    }
]
}

I can't see any issue but I'm simply not getting the expected results. Bonus question: is there a laravel/eloquent relationship way to do this?

0 likes
3 replies
Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

The problem is that you need to use whereColumn to compare columns

                    ->whereColumn('prices.valid_to', '>=', 'transactions.issue_date');
1 like
Macka's avatar
Level 1

Thank you!

I've been pulling my hair out for hours, not once seen any example use whereColumn(), but it worked!

Please or to participate in this conversation.