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.
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:
- 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 Extrahieren Sie Ihre Feldverweise als lokale Variablen. Statt die Einbettung der zB
id
Spalte in derstats
Tabelle, 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);