Tabelas JOOQ Derivados

user3567992:

Eu estou tentando expressar o seguinte SQL em JOOQ. No entanto, eu quer ter grandes problemas com tipos usando tabelas derivadas ou recebo algo que compila mas de qualquer falha a nível SQL ou mesmo em JAVA. Alguém pode me dar uma idéia de como usar tabelas derivadas corretamente neste contexto?

SELECT
    id,
    ROUND(num_realized / num_requirements, 2) AS realized_percent,
    ROUND(num_requirements / max_req, 2) AS activity_percent
FROM (
    SELECT
        requirement.project_id AS id,
        COUNT(requirement.id) AS num_requirements,
        COUNT(requirement.realized) AS num_realized
    FROM
        requirement
    GROUP BY
        requirement.project_id) AS stats
    CROSS JOIN (
        SELECT
            MAX(num_requirements) AS max_req
        FROM (
            SELECT
                requirement.project_id AS id,
                COUNT(requirement.id) AS num_requirements,
                COUNT(requirement.realized) AS num_realized
            FROM
                requirement
            GROUP BY
                requirement.project_id) AS stats) AS req_max 

A declaração funciona bem quando aplicado em SQL, mas não posso obter essa expressão em JOOQ.

Minha última tentativa foi usar

Table<Record3<Integer, Integer, Integer>> stats =
DSL.select(
    REQUIREMENT.PROJECT_ID.as("id"),
    DSL.count(REQUIREMENT.ID).as("num_requirements"),
    DSL.count(REQUIREMENT.REALIZED).as("num_realized")
).from(REQUIREMENT).groupBy(REQUIREMENT.PROJECT_ID).asTable("stats");

Table<Record2<Integer, Integer>> req_max =
    DSL.select(
        stats.field(0),
        DSL.min(stats.field(1))
    )
    .from(stats).asTable("req_max");

No entanto, eu estou recebendo erro: tipos incompatíveis:

Table<Record2<CAP#1,CAP#2>> cannot be converted to Table<Record2<Integer,Integer>>

Eu tentei um monte de diferentes técnicas, incluindo a definição do tipo de dados e usando .field (String, tipo de dados) em vez de usar "Registros", mas o que eu estou fazendo, sua ou não compilar ou falhar durante a execução em um erro desconhecido.

Eu ficaria feliz por qualquer ajuda.

Lukas Eder:

Utilizar as funções da janela em alternativa

Em geral, a auto-junta deve ser evitado sempre que possível. Em muitos casos, funções da janela pode resolver um problema muito mais elegante do que agregações em consultas aninhadas. Se você estiver usando MySQL 8, sua consulta pode ser re-escrita como:

SELECT
    requirement.project_id AS id,
    ROUND(COUNT(requirement.realized) / COUNT(requirement.id), 2) AS realized_percent,
    ROUND(COUNT(requirement.id) / MAX(COUNT(requirement.id)) OVER(), 2) AS activity_percent
FROM
    requirement
GROUP BY
    requirement.project_id    

Observe a MAX(..) OVER() função de janela, que pode agregar funções de agregação comuns como explicado aqui . Eu sei que você está usando o MySQL 5.7, que não tem apoio função de janela ainda, mas para a integralidade amor, esta resposta precisa de uma solução baseada em função de janela - talvez como uma motivação para atualizar :-)

Um monte de consultas jOOQ complexos podem ser mais simples, fazendo a consulta SQL subjacente mais simples em primeiro lugar.

O problema tabela derivada você correu para dentro

O problema é o uso de stats.field(0)e stats.field(1). A assinatura do método é

Field<?> field​(int index)

Não há nenhuma maneira jOOQ poderia fornecê-lo com segurança de tipo quando você acessar colunas de uma tabela pelo índice, portanto, o tipo de retorno é Field<?>, onde o tipo de coluna é um wild card genérico. Existem algumas soluções aqui:

  1. Evitar o tipo de segurança se você não precisa dele. Você sempre pode declarar a sua mesa Table<?> req_max. A partir do seu exemplo só, eu não tenho certeza se você precisar de qualquer tipo de segurança aqui
  2. Extrair suas referências de campo como variáveis locais. Em vez de embutir por exemplo, a idcoluna em sua statsmesa, por que não:

    Field<Integer> id = REQUIREMENT.PROJECT_ID.as("id");
    Field<Integer> numRequirements = DSL.count(REQUIREMENT.ID).as("num_requirements");
    Field<Integer> numRealized = DSL.count(REQUIREMENT.REALIZED).as("num_realized");
    

    e então usá-lo como este:

    var stats =
    DSL.select(id, numRequirements, numRealized)
       .from(REQUIREMENT)
       .groupBy(REQUIREMENT.PROJECT_ID)
       .asTable("stats");
    
    var reqMax =
    DSL.select(stats.field(id), DSL.max(stats.field(numRequirements)))
       .from(stats)
       .asTable(reqMax);
    

Acho que você gosta

Origin http://10.200.1.11:23101/article/api/json?id=478591&siteId=1
Recomendado
Clasificación