Mysql
 sql >> Datenbank >  >> RDS >> Mysql

One-to-many-Auswahl in Jooq

Mit JOIN funktioniert dafür nicht.

Ihre Abfrage wird ziemlich ineffizient sein, denn wenn Sie Joins auf diese Weise verwenden, erstellen Sie ein kartesisches Produkt zwischen den Büchern und der Artikeltabelle, was zu einem ziemlichen Speicher- und CPU-Verbrauch sowohl in der Datenbank als auch in Ihrem Java-Client führt, bevor Sie alle bedeutungslosen Kombinationen deduplizieren.

Der "richtige" SQL-Ansatz wäre die Verwendung von MULTISET wie in diesem Artikel hier beschrieben . Leider unterstützt jOOQ 3.9 MULTISET nicht noch (auch nicht viele Datenbanken). Sie sollten also zwei separate Abfragen erstellen:

  1. Alle Bücher holen
  2. Alle Artikel abrufen

Und verwenden Sie dann so etwas wie Java 8 Streams, um sie einem einzelnen Objekt zuzuordnen.

Mit MULTISET ab jOOQ 3.15

Glücklicherweise gibt es ab jOOQ 3.15 eine sofort einsatzbereite Lösung zum Verschachteln von Sammlungen in SQL mit MULTISET . Ihre Abfrage würde wie folgt aussehen:

Reflektion verwenden

List<Author> authors =
ctx.select(
      AUTHOR.ID,
      AUTHOR.NAME,
      multiset(
        select(BOOKS.TITLE)
        .from(BOOKS)
        .where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
      ).as("books"),
      multiset(
        select(ARTICLES.TITLE)
        .from(ARTICLES)
        .where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
      ).as("articles")
    )
   .from(AUTHOR)
   .where(AUTHOR.ID.eq(id))
   .fetchInto(Author.class);

Type Safe verwenden, Anzeige -hoc-Konvertierung

List<Author> authors =
ctx.select(
      AUTHOR.ID,
      AUTHOR.NAME,
      multiset(
        select(BOOKS.TITLE)
        .from(BOOKS)
        .where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
      ).as("books").convertFrom(r -> r.map(Record1::value1)),
      multiset(
        select(ARTICLES.TITLE)
        .from(ARTICLES)
        .where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
      ).as("articles").convertFrom(r -> r.map(Record1::value1))
    )
   .from(AUTHOR)
   .where(AUTHOR.ID.eq(id))
   .fetch(Records.mapping(Author::new));

Weitere Informationen zu MULTISET , lesen Sie bitte diesen Blogpost , oder die manuellen Abschnitte:

Verwendung von SQL/XML oder SQL/JSON ab jOOQ 3.14

Ab jOOQ 3.14 können Sie Sammlungen über SQL/XML oder SQL/JSON verschachteln, wenn Ihr RDBMS dies unterstützt. Sie können ein Dokument erstellen und dann etwas wie Gson, Jackson oder JAXB verwenden, um es wieder Ihren Java-Klassen zuzuordnen. Zum Beispiel:

List<Author> authors =
ctx.select(
      AUTHOR.ID,
      AUTHOR.NAME,
      field(
        select(jsonArrayAgg(BOOKS.TITLE))
        .from(BOOKS)
        .where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
      ).as("books"),
      field(
        select(jsonArrayAgg(ARTICLES.TITLE))
        .from(ARTICLES)
        .where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
      ).as("articles")
    )
   .from(AUTHOR)
   .where(AUTHOR.ID.eq(id))
   .fetchInto(Author.class);

Beachten Sie, dass JSON_ARRAYAGG() aggregiert leere Mengen zu NULL , nicht in einen leeren [] . Wenn das ein Problem ist, verwenden Sie COALESCE()