Our codebase is in honeysql 1.x version and I am trying to get this query working
SELECT *
FROM
schemes s
LEFT JOIN progress p ON p.scheme_id = s.id
AND s.term = 1
AND p.date > '2023-04-27'
WHERE
p.driver_id = '123'
ORDER BY p.date DESC
LIMIT 10 OFFSET 0;
and till left join it’s working as below:
(-> (sqle/select* [:*])
(helpers/from [:schemes :s])
(helpers/left-join [:progress :p] [:= :p.scheme-id :s.id])
(honeysql.core/format))
but I am not sure how to add the
AND s.term = 1
AND p.date > '2023-04-27'
part in honeysql(I want it to be there instead of where condition because it optimizes the query by filtering records at join time).Wrap [:= ...] in [:and ...].
Also, are you sure about that "it optimizes the query" statement? I would be rather surprised if that's the case since it seems to be a very obvious optimization that a query planner can do on its own. Have you run EXPLAIN ANALYZE on that query and compared it to the one where the conditions are in the WHERE clause?
tried placing [:and [:= :s.term 1]] inside the left-join as well as after it but it’s not working:
(-> (sqle/select* [:*])
(sqlh/from [:schemes :s])
(sqlh/left-join [:progress :p] [:= :p.scheme-id :s.id])
([:and [:= :s.term 1]])
(sqlc/format))
is giving ; Key must be integer error.And yes, the query with AND statements is giving less execution time on average than the query with “WHERE” conditions. It was suggested by a colleague and I was also surprised(It’s 30-40% improvement) on running it with explain analyze
I meant to wrap the existing := in :and: (sqlh/left-join [...] [:and [:= ...] [:= ...]]).
> And yes, the query with AND statements is giving less execution time on average Intersting. Are there differences in actual plans? On my end, I can only see "hash join" vs "hash right join" and they don't result in any difference time-wise.
Oh, hold on - in your case it's actually quite important because it's a left join and not an inner join. Putting the conditions in a different place will result in different results. Didn't happen on my end because there were always entries in the joined table for any row in the main table.
So, there shouldn't be a difference if you have an inner join - both result- and performance-wise.
(-> (sqle/select* [:*])
(sqlh/from [:schemes :s])
(sqlh/left-join [:progress :p] [:= :p.scheme-id :s.id] [:and [:= :s.term 1]])
(sqlc/format))
["SELECT * FROM schemes s LEFT JOIN progress p ON p.scheme_id = s.id"]
that’s not working either, it seems like it’s just ignoring the end partWhy do you keep putting that original [:= ...] outside of the [:and ...]?
It should be (sqlh/left-join [:progress :p] [:and [:= :p.scheme-id :s.id] [:= :s.term 1]]).
In other words, you need to be joining on :and, not on :=.
I see, that worked!
Thanks a lot!