1

I'm using Laravel 5.2 and have a sql query using the query builder functions and have broken a query when switching from a MySQL database to PostgreSQL. The query is meant to get all locations within a certain number of miles of a latitude and longitude.

    $locations = Location::select(
        DB::raw("*,
            ( 3959 * acos( cos( radians(?) ) *
                cos( radians( lat) )
                * cos( radians( long ) - radians(?)
                ) + sin( radians(?) ) *
                sin( radians( lat ) ) )
            ) AS distance"))
        ->having("distance", "<", $distance)
        ->orderBy("distance")
        ->setBindings([$latitude, $longitude, $latitude])
        ->get();

Once switching to the PostgreSQL data source, I get this error:

QLSTATE[42703]: Undefined column: 7 ERROR: column "distance" does not exist
LINE 7: ) AS distance from "locations" having "distance" < $4 o...
^ (SQL: select *,
( 3959 * acos( cos( radians(37.7959362) ) *
cos( radians( lat ) )
* cos( radians( long ) - radians(-122.4000032)
) + sin( radians(37.7959362) ) *
sin( radians( lat ) ) )
) AS distance from "locations" having "distance" < 15 order by "distance" asc)

What would be the best way to fix this problem. I know it's a difference in the SQL syntax between MySQL and Postgres that is created by Laravel but I'm tearing my hair out trying to figure out how to fix this error.

Any help would be greatly appreciated!

1 Answer 1

1

The issue is your having clause. PostgreSQL does not allow using a derived column (or column alias) in the having clause, whereas MySQL does (as long as you have MySQL Extensions to Group By enabled, which is enabled by default).

One option to get around this restriction is to use a derived table, so that the field is available for the having clause. Something like below (warning: completely untested):

$locations = Location::from(DB::raw("(select *,
        ( 3959 * acos( cos( radians(?) ) *
            cos( radians( lat) )
            * cos( radians( long ) - radians(?)
            ) + sin( radians(?) ) *
            sin( radians( lat ) ) )
        ) AS distance from locations) as t"))
    ->having("distance", "<", $distance)
    ->orderBy("distance")
    ->setBindings([$latitude, $longitude, $latitude])
    ->get();
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @patricus! I was able to get to the solution using your suggestion to use a derived table. I had to add a group by clause that looked like this: ->groupBy(DB::raw('id, title, address_1 ...')).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.