Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support LATERAL joins #1425

Closed
ashleyw opened this issue May 12, 2016 · 7 comments

Comments

@ashleyw
Copy link

commented May 12, 2016

http://www.postgresql.org/docs/9.3/static/queries-table-expressions.html#QUERIES-LATERAL
http://blog.heapanalytics.com/postgresqls-powerful-new-join-type-lateral/

It would be immensely valuable when combined with subquery, for instance getting the most recent comments on a post:

post = Repo.one(
  from p in Post,
  where: p.id == 123,
  lateral_join: cs in subquery(
    from c in Comment,
    order_by: [desc: c.inserted_at],
    where: c.post_id == p.id,
    limit: 5
  ),
  preload: [comments: cs]
)

It doesn't appear that using INNER JOIN LATERAL is possible even with a fragment, since join wraps the fragment in additional parentheses (i.e. INNER JOIN (LATERAL (SELECT …))), which isn't valid AFAIK.

@josevalim

This comment has been minimized.

Copy link
Member

commented May 13, 2016

If you would like to send a PR, it would be appreciated. :)

@ashleyw

This comment has been minimized.

Copy link
Author

commented May 13, 2016

I dived in and took a look, but I don't think I'm capable of implementing this. I've only been using Elixir for a few months. :)

@josevalim

This comment has been minimized.

Copy link
Member

commented May 14, 2016

@ashleyw no problem, we will tackle this after 2.0 is out, unless someone decides to handle it first. :)

@aphillipo

This comment has been minimized.

Copy link

commented May 16, 2016

I started having a look into this yesterday and I came up with two ways to do it:

  1. Change the Join Qualifier (qual) to include the join type (INNER), the JOIN keyword and optionally LATERAL, which would make the atom something like: :inner_join_lateral :left_join_lateral - we would need to change the adaptors to support this, removing " JOIN " which makes the code less explicit.

  2. Change the %JoinExpr to add a :join_qual_suffix part of the struct, this would support other possible queries than LATERAL in the <join_qualifier> JOIN <:join_qual_suffix> should they exists in the future. However implementing this seems like there are a hell of a lot of moving parts to change; this would turn all of the join building macros from /7 to /8 and I started getting lost in the changes.

Obviously it's a classic trade off:

  1. is simpler but feels very inflexible and if there is anything that adds things it means more entries for each supported join type

  2. gives extra possibilities for the future but if I'm honest seems difficult!

Let me know if you want me to push through with one of these and maybe I can ask questions if I get stuck! Thanks!

EDIT: 3) Looking at the definition of LATERAL it seems to only apply to subqueries so maybe the simplest way would be to change the params of a subquery( , lateral: true) which would be even simpler and not touch any of the join code. I think that is the one!

@ashleyw

This comment has been minimized.

Copy link
Author

commented May 16, 2016

Totally out of my depth here.. but am I right in thinking subquery needs adapting to allow passing in the parent variable? That's what I struggled with when I attempted to implement this.

@josevalim

This comment has been minimized.

Copy link
Member

commented May 16, 2016

@ashleyw that would be very tricky to implement indeed. Subqueries today cannot interact with elements outside of the query. Although you can use fragments when writing your lateral joins (and that should work fine).

@bernardoamc

This comment has been minimized.

Copy link
Contributor

commented Jun 18, 2016

Forgot to reference this issue in the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.