Mofolumike
Mofolumike

Reputation: 53

Laravel - Column not found: 1054 Unknown column in Laravel Query

I tried to run a Laravel query that selects a particular field that appears more than once, and I got the error below.

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'no_of_service' in 'having clause' (SQL: select count(*) as aggregate from cloudsubscriptions inner join service_package on cloudsubscriptions.package_id = service_package.id group by cloudsubscriptions.msisdn, service_package.title having no_of_service > 1)

$subscribers = Cloudsubscriptions::join("service_package", 
    "cloudsubscriptions.package_id", "=", "service_package.id")
    ->select("cloudsubscriptions.msisdn", "cloudsubscriptions.service_name", 
        "service_package.title",
        DB::raw("COUNT(cloudsubscriptions.msisdn) as 'no_of_service'"))
    ->groupBy("cloudsubscriptions.msisdn", "service_package.title")
    ->having('no_of_service', '>', 1)
    ->get();

I expect to see fields that appear more than once.

Upvotes: 1

Views: 5900

Answers (1)

Bogdan
Bogdan

Reputation: 44526

I'm pretty sure you're using paginate() in your code and not get() as you posted. And when Laravel generates the necessary data for pagination, it overrides the SELECT part of your statement with:

SELECT count(*) as aggregate

This is used to get the total entries count. That is very obvious from the SQL part of your error message:

SQL: select count(*) as aggregate from cloudsubscriptions inner join service_package on cloudsubscriptions.package_id = service_package.id group by cloudsubscriptions.msisdn, service_package.title having no_of_service > 1

That of course overwrites your no_of_service alias definition, which can no longer be found in your HAVING statement when the total count is done by the paginator.


To work around this, you could use the aggregate function directly in your HAVING statement without the alias:

$subscribers = Cloudsubscriptions::join("service_package", 
    "cloudsubscriptions.package_id", "=", "service_package.id")
    ->select(
        "cloudsubscriptions.msisdn", 
        "cloudsubscriptions.service_name", 
        "service_package.title",
        DB::raw("COUNT(cloudsubscriptions.msisdn) as 'no_of_service'"))
    ->groupBy("cloudsubscriptions.msisdn", "service_package.title")
    // Use the COUNT aggregate function here as well
    ->havingRaw('COUNT(cloudsubscriptions.msisdn) > 1')
    ->get();

It is a little annoying to have to duplicate that logic, but at least you can make use of the Laravel Pagination which is a much bigger gain.

IMPORTANT NOTE! Make sure to use bindings with havingRaw and other raw methods if the value comes from user input.


UPDATE

Since you're using Eloquent as the starting point for your query, your can make use of this great package made by Roy Duineveld, which fixes the issue present in the paginator and allows you to use the alias in your HAVING statement. You can use it by simply including a trait in your model:

use Illuminate\Database\Eloquent\Model;
use JustBetter\PaginationWithHavings\PaginationWithHavings;

class Cloudsubscriptions extends Model
{
    use PaginationWithHavings;
}

And now you can use your original query code without any problems.

Upvotes: 2

Related Questions