question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Restrictions in union with with and withRecursive

See original GitHub issue

The postgres with recursive query can refer to its own output. The syntax can look like this

WITH RECURSIVE t(n) AS (
    VALUES (1)
  UNION ALL
    SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;

The kysely union method does only take a querybuilder as input which is not type aware of its surroundings. Hence the following does not work:

db.withRecursive("t", qb =>
  qb
    .selectFrom(sql<{ n: number }>`(select 1 as n)`.as("q"))
    .select("q.n")
    .unionAll(qb =>
      qb
        .selectFrom("t")
        .select(sql<number>`n+1`.as("n"))
        .where("t.n", "<", 100)
    )
);

because the unionAll does not accept a querybuilder function. What does work, but has less type support, is using the raw sql builder in the unionAll

db.withRecursive("t", qb =>
  qb
    .selectFrom(sql<{ n: number }>`(select 1 as n)`.as("q")
)
.select("q.n")
.unionAll(sql`select n+1 as n from t where t.n < 100`);

 

The restriction in the union method makes it also harder to access the same with query in two union queries like this

with t as (
    select 1 as n
)
select * from t
union all select * from t

Here, the following does not work:

db.with("t", qb =>
    qb.selectFrom(sql<{ n: number }>`(select 1 as n)`.as("q")).select("q.n")
  )
.selectFrom("t")
.select("n")
.unionAll(qb => qb.selectFrom("t").select("n"));

and even the following (which is not ideal) is not possible because of missing brackets in the resulting query

const qb1 = db
  .with("t", qb =>
    qb
      .selectFrom(sql<{ n: number }>`(select 1 as n)`.as("q"))
      .select("q.n")
  )
  .selectFrom("t")
  .select("n");

const qb2 = db
  .with("t", qb =>
    qb
      .selectFrom(sql<{ n: number }>`(select 1 as n)`.as("q"))
      .select("q.n")
  )
  .selectFrom("t")
  .select("n");

const qbUnion = qb1.unionAll(qb2);

which results in the following query

with "t" as (select "q"."n" from (select 1 as n) as "q") select "n" from "t" union all with "t" as (select "q"."n" from (select 1 as n) as "q") select "n" from "t"

throwing a syntax error:

syntax error at or near “with”

 

Are there any plans on allowing a callback function in the union and unionAll methods allowing us to have access to the typings?

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
koskimascommented, Aug 15, 2022

So I think here’s how to fix your query:

db.withRecursive("t(n)", qb =>
  qb
    .selectFrom(sql<{ n: number }>`(select 1 as n)`.as("q"))
    .select("q.n")
    .unionAll(
      qb
        .selectFrom("t")
        .select(sql<number>`n+1`.as("n"))
        .where("t.n", "<", 100)
    )
);
1reaction
koskimascommented, Aug 15, 2022

I’m not sure I understood your problem, but this works:

const query = nodeTrx
  .withRecursive('ancestors(name, parent)', (db) =>
    db
      .selectFrom('node')
      .where('name', '=', 'node1')
      .select(['name', 'parent'])
      .unionAll(
        db
          .selectFrom('node')
          .innerJoin('ancestors', 'node.name', 'ancestors.parent')
          .select(['node.name', 'node.parent'])
      )
  )
  .selectFrom('ancestors')
  .select('name')

kysely is able to parse the ancestors(name, parent) name into a table that has name and parent columns, and you are able to reference it inside and outside the callback.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Restrictions in union with with and withRecursive - PullAnswer
I'm not sure I understood your problem, but this works: const query = nodeTrx .withRecursive('ancestors(name, parent)', (db) => db .
Read more >
Can I use… with recursive (… union [distinct] …) - Modern SQL
Union [distinct] within with recursive can be used to omit duplicate rows and thus preventing infinite loops. WITH RECURSIVE path (a, b) AS...
Read more >
7.8. WITH Queries (Common Table Expressions) - PostgreSQL
For example, this query would loop forever without the LIMIT : WITH RECURSIVE t(n) AS ( SELECT 1 UNION ALL SELECT n+1 FROM...
Read more >
WITH Clause Recursion - Vertica
Executes the WITH RECURSIVE clause: Evaluates the non-recursive term SELECT 1, and places the result set—1—in nums . Iterates over the UNION ALL...
Read more >
13.2.20 WITH (Common Table Expressions)
This is a MySQL restriction that is lifted in MySQL 8.0.14, ... WITH RECURSIVE cte (n) AS ( SELECT 1 UNION ALL SELECT...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found