JOOQ Derived Tables

user3567992:

Ich versuche, die folgende SQL in jOOQ auszudrücken. Allerdings habe ich entweder massive Probleme mit den Typen mit abgeleiteten Tabellen oder ich etwas, das kompiliert aber entweder auf SQL-Ebene ausfällt oder sogar in JAVA. Kann mir jemand eine Idee geben, wie abgeleitete Tabellen in diesem Zusammenhang richtig zu benutzen?

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 

Die Anweisung funktioniert gut, wenn in SQL angewandt, aber ich kann diesen Ausdruck in jOOQ nicht bekommen.

Mein letzter Versuch wurde mit

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

Allerdings Fehler Ich erhalte: inkompatible Typen:

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

Ich habe versucht, eine Reihe von verschiedenen Techniken, einschließlich dem Datentypen Definition und Verwendung .field (String, Datentyp) anstelle von „Records“, aber was auch immer ich tue, sein entweder nicht kompiliert oder ausfällt, während in einem unbekannten Fehler ausgeführt wird.

Ich würde für jede Hilfe freuen.

Lukas Eder:

Mit Fensterfunktionen statt

Im Allgemeinen Joins-Selbst sollten wann immer Sie können vermieden werden. In vielen Fällen können Fensterfunktionen lösen ein Problem wesentlich eleganter als Aggregationen in verschachtelten Abfragen. Wenn Sie MySQL wurden 8, Ihre Abfrage neu geschrieben werden kann als:

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    

Beachten Sie die MAX(..) OVER() Fensterfunktion, die normale Aggregationsfunktionen aggregieren kann wie hier erläutert . Ich weiß , dass du mit MySQL 5.7, die noch keine Fensterfunktion Unterstützung, aber der Vollständigkeit halber, diese Antwort muss eine Fensterfunktion basierte Lösung - vielleicht als Motivation zu aktualisieren :-)

Viele komplexe jOOQ Abfragen können, indem sie die zugrunde liegende SQL-Abfrage einfacher in erster Linie einfacher gemacht werden.

Die abgeleitete Tabelle Problem, das Sie lief in

Das Problem ist , Ihre Benutzung stats.field(0)und stats.field(1). Die Methodensignatur ist

Field<?> field​(int index)

Es gibt keine Möglichkeit jOOQ könnten Sie mit Typ - Sicherheit, wenn Sie eine Tabellenspalten durch den Index zugreifen, daher auch der Rückgabetyp ist Field<?>, wobei der Spaltentyp ein generischer Platzhalter ist. Es gibt ein paar Lösungen hier:

  1. Vermeiden Sie die Typsicherheit , wenn Sie es nicht brauchen. Sie können jederzeit Ihre Tabelle deklarieren Table<?> req_max. Von Ihrem Beispiel allein, ich bin nicht sicher , ob Sie irgendeine Art Sicherheit hier brauchen
  2. Extrahieren Sie Ihre Feldverweise als lokale Variablen. Statt die Einbettung der zB idSpalte in der statsTabelle, warum nicht:

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

    und verwenden Sie es dann wie folgt aus:

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

Ich denke du magst

Origin http://10.200.1.11:23101/article/api/json?id=478586&siteId=1
Empfohlen
Rangfolge