jOOQ - Concisely Representing Both Columns and Aggregate/Window Functions in a Query

别说谁变了你拦得住时间么 提交于 2019-12-23 15:26:29

问题


This post comes as a result of a comment I left on a similar question: https://stackoverflow.com/a/19860271/2308858

I'm using PostgreSQL and jOOQ 3.4 and trying to represent the following SQL query in jOOQ:

SELECT *, COUNT(*) OVER() 
FROM table1 t1
JOIN table2 t2 ON (t1.id = t2.id)
JOIN table3 t3 ON (t1.otherId = t3.otherId)

I like how Postgres lets me concisely represent "all columns plus the count column" with nothing more than SELECT *, COUNT(*) OVER(). But when I try to represent this same query in jOOQ, the most concise way I can do is:

create.select( TABLE1.fields() ).select( TABLE2.fields() ).select( TABLE3.fields() ).select( count().over() )
   .from( TABLE1 )
   .join( TABLE2 ).on( TABLE1.ID.equal( TABLE2.ID ))
   .join( TABLE3 ).on( TABLE1.OTHER_ID.equal( TABLE3.OTHER_ID ))

Ideally, I'd write this instead:

create.select().select( count().over() )
   .from( TABLE1 )
   .join( TABLE2 ).on( TABLE1.ID.equal( TABLE2.ID ))
   .join( TABLE3 ).on( TABLE1.OTHER_ID.equal( TABLE3.OTHER_ID ))

But this doesn't seem to work. Any thoughts on how I can do this?


回答1:


This solution, which you've found yourself, is indeed the way to go with the jOOQ API:

create.select( TABLE1.fields() )
      .select( TABLE2.fields() )
      .select( TABLE3.fields() )
      .select( count().over() )
      ...

It conceptually corresponds to this valid SQL query:

SELECT table1.*, table2.*, table3.*, COUNT(*) OVER()
...

Manipulating the jOOQ "model API":

But if this is annoying to you, you can also work around this issue with this little trick:

// Get access to the "model API" from a statement without any SELECT fields
SelectQuery<?> select =
create.select()
      .from( TABLE1 )
      .join( TABLE2 ).on( TABLE1.ID.equal( TABLE2.ID ))
      .join( TABLE3 ).on( TABLE1.OTHER_ID.equal( TABLE3.OTHER_ID ))
      .getQuery();

// Copy all fields from the SELECT statement:
List<Field<?>> fields = new ArrayList<>(select.getSelect());

// And explicitly add them:
select.addSelect(fields);
select.addSelect(count().over());

This is equally verbose as your original attempt, but might be a bit simpler to use, generically.

Using a derived table

Of course, you could also simply write the following, equivalent SQL query, which would be more standard SQL:

SELECT t.*, COUNT(*) OVER()
FROM (
  SELECT *
  FROM table1 t1
  JOIN table2 t2 ON (t1.id = t2.id)
  JOIN table3 t3 ON (t1.otherId = t3.otherId)
) t

With jOOQ, this would translate to:

Table<?> t = select()
            .from( TABLE1 )
            .join( TABLE2 ).on( TABLE1.ID.equal( TABLE2.ID ))
            .join( TABLE3 ).on( TABLE1.OTHER_ID.equal( TABLE3.OTHER_ID ))
            .asTable("t");

create.select(t.fields(), count().over())
      .from(t);

Support for the asterisk

In a future version of jOOQ, the actual asterisk (*) might be supported explicitly through the jOOQ API. At this point, it is a bit unclear how that can be achieved syntactically, though.

On a side-note:

I have always found it very curious that PostgreSQL allows this syntax here:

SELECT *, COUNT(*) OVER() 
...

It is hardly ever supported by SQL engines and a bit "unpredictable". Neither does the SQL standard allow for a "standalone asterisk" to be combined with other column expressions.



来源:https://stackoverflow.com/questions/25313595/jooq-concisely-representing-both-columns-and-aggregate-window-functions-in-a-q

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!