Mysql
 sql >> Database >  >> RDS >> Mysql

Seleziona uno a molti in Jooq

Utilizzando JOIN non funziona per questo.

La tua query sarà piuttosto inefficiente perché se utilizzi i join in questo modo, stai creando un prodotto cartesiano tra i libri e la tabella degli articoli, con conseguente consumo di memoria e CPU sia nel database che nel client Java, prima di deduplicare tutte le combinazioni senza senso.

L'approccio SQL "corretto" sarebbe quello di utilizzare MULTISET come descritto in questo articolo qui . Sfortunatamente, jOOQ 3.9 non supporta MULTISET ancora (né molti database). Quindi, dovresti creare due query separate:

  1. Recupero di tutti i libri
  2. Recupero di tutti gli articoli

E poi usa qualcosa come Java 8 Streams per mapparli in un singolo oggetto.

Utilizzo di MULTISET a partire da jOOQ 3.15

Fortunatamente, a partire da jOOQ 3.15, esiste una soluzione pronta all'uso per nidificare le raccolte in SQL utilizzando MULTISET . La tua richiesta sarebbe simile a questa:

Utilizzo della riflessione

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

Utilizzando type safe, ad -conversione ad hoc

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

Per ulteriori informazioni su MULTISET , fai riferimento a questo post del blog , o le sezioni del manuale:

Utilizzo di SQL/XML o SQL/JSON a partire da jOOQ 3.14

A partire da jOOQ 3.14, puoi nidificare le raccolte tramite SQL/XML o SQL/JSON, se il tuo RDBMS lo supporta. Puoi produrre un documento e quindi utilizzare qualcosa come Gson, Jackson o JAXB per mapparlo di nuovo alle tue classi Java. Ad esempio:

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

Nota che JSON_ARRAYAGG() aggrega gli insiemi vuoti in NULL , non in un [] vuoto . Se questo è un problema, usa COALESCE()