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

Needed: unnest WITH ORDINALITY #335

Open
virusdave opened this issue Mar 7, 2017 · 8 comments
Open

Needed: unnest WITH ORDINALITY #335

virusdave opened this issue Mar 7, 2017 · 8 comments

Comments

@virusdave
Copy link

virusdave commented Mar 7, 2017

Let's say I have 2 sql array literals (in scala as lists): val a = List("a", "b", "c") and val b = List(1, 2, 3)

I want to do a zipJoin on the unnest of these two, to produce:

a, 1
b, 2
c, 3

Trying something naive like:
val c = Query(a.unnest).zipJoin(Query(b.unnest)) doesn't do the right thing, due to how zipJoin and unnest are implemented! Instead, it gives the cross product of these two sets.

Specifically, the construct SELECT UNNEST(...) instead of SELECT * FROM (UNNEST(...)), when combined with ROW_NUMBER gives all rows the value 1.

Investigating a bit, it seems like the "correct" method to do this in postgres is by using the syntax SELECT * FROM (UNNEST(...) WITH ORDINALITY), which will then be guaranteed to give me back the items from the input array with correctly applied indices, which could then be joined on.

How is this possible using slick-pg, or do I need to use a sql"" style query?

@tminglei
Copy link
Owner

tminglei commented Mar 9, 2017

@virusdave slick-pg can't resolve this. Maybe you should try sql"".

@virusdave
Copy link
Author

the problem there is that sql"...".as[] returns a DBIO, which isn't really helpful, since one could always have just unnested the arrays locally. What is really needed is a way to get them unnested in the middle of a query.

For instance, consider a db table that has an index on 2 columns, A,B.
What we're trying to achieve is a way to specify a discrete set of (A,B) values to a query. However, for performance reasons, the slick query needs to be precompiled, so using things like inSet are a nonstarter.

If we could accomplish this unnesting, then the entire query can be precompiled just fine. The final query would look something like:

myTable.join {
  listOfAs.unnestWithOrdinality
    .join(listOfBs.unnestWithOrdinality)
    .on(_._2 === _._2)
    .map { case (as, bs) => (as._1, bs._1)
}.on { case (tab, params) =>
  tab.a === params._1 && tab.b === params._2
}.map { case (tab, _) => tab }

// do other stuff with the now-filtered table

Such a query would be precompilable and still be parameterizable with parameter sets of cardinality unknown at compile time, which is a HUGE problem in slick now.

If this unnesting functionality isn't possible in slick-pg currently, can you add it? It would solve a critical use case with high performance.

@tminglei
Copy link
Owner

tminglei commented Mar 11, 2017

I'll try. But with ordinality is a general feature, I'd better to make it general.

@tminglei
Copy link
Owner

Well, the generated SELECT UNNEST(...) instead of SELECT * FROM (UNNEST(...)) is a problem. It must be resolved before add WITH ORDINALITY support.

@virusdave
Copy link
Author

Yup, for sure! I think i could possibly add the with ordinality support myself at this point, but getting the query restructured like that was a head-scratcher for me, which is why i made this request here 😀

Does it look like it'll be doable?

@tminglei
Copy link
Owner

No, I can't let it generate SELECT * FROM (UNNEST(...)), then I can't implement with ordinality.

@SergeyZharikhin
Copy link

SergeyZharikhin commented Dec 15, 2020

Hello, @virusdave! Did you manage to come up with a workaround for this?

@strokyl
Copy link

strokyl commented Mar 4, 2021

Have you try using Query(a.unnest).subquery.zipJoin(Query(b.unnest)).subquery. I had a somewhat similar issue and resolved it like that: #501

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

No branches or pull requests

4 participants