Mysql
 sql >> Base de données >  >> RDS >> Mysql

Sélection un à plusieurs dans Jooq

Utiliser JOIN ne fonctionne pas pour cela.

Votre requête sera plutôt inefficace car si vous utilisez des jointures de cette façon, vous créez un produit cartésien entre les livres et la table des articles, ce qui entraîne une certaine consommation de mémoire et de CPU à la fois dans la base de données et dans votre client Java, avant de dédupliquer toutes les combinaisons inutiles.

L'approche SQL "correcte" serait d'utiliser MULTISET comme décrit dans cet article ici . Malheureusement, jOOQ 3.9 ne prend pas en charge MULTISET encore (ni beaucoup de bases de données). Vous devez donc créer deux requêtes distinctes :

  1. Récupérer tous les livres
  2. Récupération de tous les articles

Et utilisez ensuite quelque chose comme Java 8 Streams pour les mapper dans un seul objet.

Utiliser MULTISET à partir de jOOQ 3.15

Heureusement, à partir de jOOQ 3.15, il existe une solution prête à l'emploi pour imbriquer des collections dans SQL en utilisant MULTISET . Votre requête ressemblerait à ceci :

Utiliser la réflexion

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

En utilisant le type safe, ad conversion aléatoire

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

Pour plus d'informations sur MULTISET , veuillez consulter cet article de blog , ou les sections du manuel :

Utilisation de SQL/XML ou SQL/JSON à partir de jOOQ 3.14

À partir de jOOQ 3.14, vous pouvez imbriquer des collections via SQL/XML ou SQL/JSON, si votre SGBDR le prend en charge. Vous pouvez produire un document, puis utiliser quelque chose comme Gson, Jackson ou JAXB pour le mapper à vos classes Java. Par exemple :

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

Notez que JSON_ARRAYAGG() agrège les ensembles vides en NULL , pas dans un [] vide . Si c'est un problème, utilisez COALESCE()