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 · 8 comments
Closed

Support LATERAL joins #1425

ashleyw opened this issue May 12, 2016 · 8 comments

Comments

@ashleyw
Copy link

ashleyw 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
Copy link
Member

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

@ashleyw
Copy link
Author

ashleyw 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
Copy link
Member

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

@aphillipo
Copy link

aphillipo 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
Copy link
Author

ashleyw 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
Copy link
Member

@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
Copy link
Contributor

Forgot to reference this issue in the PR.

@ukrbublik
Copy link

ukrbublik commented Feb 6, 2020

Is there any workaround to use subquery with latter joins?
Fragments for latter joins makes not much sense :(

Why I can't use binding p inside subquery as in example in first 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,
  )
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants