JOOQ dérivés Tableaux

user3567992:

J'essaie d'exprimer l'instruction SQL suivante dans JOOQ. Cependant, je soit d'énormes problèmes avec des types à l'aide de tables dérivées ou je reçois quelque chose qui compile, mais échoue soit au niveau SQL ou même en JAVA. Quelqu'un peut-il me donner une idée comment utiliser correctement les tables dérivées dans ce contexte?

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 

L'énoncé fonctionne très bien lorsqu'elle est appliquée dans SQL mais je ne peux pas obtenir cette expression dans JOOQ.

Mon dernier essai utilisait

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");

Cependant, je reçois l'erreur: types incompatibles:

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

J'ai essayé un tas de différentes techniques, y compris la définition du type de données et en utilisant .field (String, type de données) au lieu d'utiliser « Records », mais tout ce que je fais, soit son pas compiler ou échoue lors de l'exécution d'une erreur inconnue.

Je serais heureux pour toute aide.

Lukas Eder:

Utilisation des fonctions de fenêtre à la place

En général, Autojointures doit être évitée autant que vous le pouvez. Dans de nombreux cas, les fonctions de fenêtre peut résoudre un problème beaucoup plus élégante que agrégations dans les requêtes imbriquées. Si vous utilisez MySQL 8, votre requête peut être réécrite comme:

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    

Notez la MAX(..) OVER() fonction de fenêtre, qui peut regrouper les fonctions d'agrégation ordinaires comme expliqué ici . Je sais que vous utilisez MySQL 5.7, qui n'a pas de support de la fonction de fenêtre encore, mais pour être complet, cette réponse a besoin d' une solution basée sur la fonction de fenêtre - peut - être comme une motivation pour améliorer :-)

Beaucoup de requêtes complexes jOOQ peut être rendu plus simple en faisant la requête SQL sous-jacente plus simple en premier lieu.

Le problème de la table dérivée laquelle vous avez été

Le problème est votre utilisation stats.field(0)et stats.field(1). La signature de la méthode est

Field<?> field​(int index)

Il n'y a aucun moyen jOOQ pourrait vous fournir la sécurité de type lorsque vous accédez à des colonnes d'une table par index, d' où le type de retour est Field<?>, où le type de colonne est une carte sauvage générique. Il y a quelques solutions ici:

  1. Évitez la sécurité de type si vous ne avez pas besoin. Vous pouvez toujours déclarer votre table Table<?> req_max. A partir de votre seul exemple, je ne sais pas si vous avez besoin d'ici la sécurité de type
  2. Extrait vos références sur le terrain en tant que variables locales. Au lieu d'incorporer par exemple la idcolonne de votre statstable, pourquoi ne pas:

    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");
    

    puis l'utiliser comme ceci:

    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);
    

Je suppose que tu aimes

Origine http://10.200.1.11:23101/article/api/json?id=478594&siteId=1
conseillé
Classement