Estou tentando agrupar com base em uma expressão case. O JOOQ abaixo parece ser a coisa certa a fazer e produz mais ou menos o SQL que espero. Do banco de dados 'sakila' (por favor, desculpe meu Kotlin, que tem que escapar 'when' e 'as'):
val shared = `when`(ACTOR.LAST_NAME.like("A%"), "A")
.`when`(ACTOR.LAST_NAME.like("B%"), "B")
.otherwise("C")
val r = ctx.select(
count(), shared.`as`("code")
)
.from(ACTOR)
.groupBy(shared)
.fetch()
O SQL Server 2017 Express (v14) reclama:
A coluna 'DTB_DEV_SAKILA.dbo.actor.last_name' é inválida na lista de seleção porque não está contida em uma função de agregação ou na cláusula GROUP BY.
O que é uma surpresa, porque é. Aqui está o debug/stacktrace completo (eu o semi-formatei para legibilidade):
Exception in thread "main" org.jooq.exception.DataAccessException: SQL [
select count(*),
case when [DTB_DEV_SAKILA].[dbo].[actor].[last_name] like ? then ?
when [DTB_DEV_SAKILA].[dbo].[actor].[last_name] like ? then ?
else ? end [code]
from [DTB_DEV_SAKILA].[dbo].[actor]
group by case when [DTB_DEV_SAKILA].[dbo].[actor].[last_name] like ? then ?
when [DTB_DEV_SAKILA].[dbo].[actor].[last_name] like ? then ? else ? end
]; Column 'DTB_DEV_SAKILA.dbo.actor.last_name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
O mais irritante é que se eu recortar/colar a consulta (conforme gerada pelo stacktrace) e substituir o espaço reservado/instrução preparada '?' por valores reais, o SSMS a executa perfeitamente.
select
count(*),
case
when [DTB_DEV_SAKILA].[dbo].[actor].[last_name] like 'A%'
then 'A'
when [DTB_DEV_SAKILA].[dbo].[actor].[last_name] like 'B%'
then 'B'
else 'C'
end as code
from
[DTB_DEV_SAKILA].[dbo].[actor]
group by
case
when [DTB_DEV_SAKILA].[dbo].[actor].[last_name] like 'A%' then 'A'
when [DTB_DEV_SAKILA].[dbo].[actor].[last_name] like 'B%' then 'B'
else 'C'
end as code
Notas:
- se eu usar
inline()
a função do JOOQ para me livrar dos '?'s da Declaração Preparada (ou seja, variáveis de ligação), funciona perfeitamente; - não há trégua usando IIF em vez de CASE WHE N... ele reclama da mesma coisa.
Mas esse código (sem variáveis de vinculação, eu acho, apenas referências de coluna) funciona perfeitamente:
val shared = length(ACTOR.LAST_NAME)
val r = ctx.select(
count(), shared.`as`("voluminousness")
)
.from(ACTOR)
.groupBy(shared)
.fetch()
Então o problema é algum nexo de agrupamento por uma declaração de caso, ao tentar compilar um PreparedStatement
.
Parece mais um problema de JDBC/SQL Server do que de JOOQ. Mas um usuário de JOOQ normalmente adotaria uma abordagem diferente da que está aqui? Existe uma solução alternativa? Outros bancos de dados têm essa limitação de agrupamento por a CASE
?
JOOQ 3.19.10, MS JDBC 12.8.1.jre11, SQL Server 2017 (v14.0.2065)