sql >> Base de Datos >  >> RDS >> Mysql

Selección de uno a muchos en Jooq

Usando JOIN no funciona para esto.

Su consulta será bastante ineficiente porque si está utilizando uniones de esta manera, está creando un producto cartesiano entre la tabla de libros y la de artículos, lo que genera bastante memoria y consumo de CPU tanto en la base de datos como en su cliente Java, antes de desduplicar todas las combinaciones sin sentido.

El enfoque de SQL "correcto" sería usar MULTISET como se describe en este artículo aquí . Lamentablemente, jOOQ 3.9 no es compatible con MULTISET todavía (ni muchas bases de datos). Por lo tanto, debe crear dos consultas separadas:

  1. Buscando todos los libros
  2. Obteniendo todos los artículos

Y luego use algo como Java 8 Streams para mapearlos en un solo objeto.

Usando MULTISET a partir de jOOQ 3.15

Afortunadamente, a partir de jOOQ 3.15, hay una solución lista para usar para anidar colecciones en SQL usando MULTISET . Su consulta se vería así:

Usando la reflexión

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

Usando type safe, ad conversión -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));

Para obtener más información sobre MULTISET , consulte esta entrada de blog , o las secciones del manual:

Usando SQL/XML o SQL/JSON a partir de jOOQ 3.14

A partir de jOOQ 3.14, puede anidar colecciones a través de SQL/XML o SQL/JSON, si su RDBMS lo admite. Puede producir un documento y luego usar algo como Gson, Jackson o JAXB para mapearlo de nuevo a sus clases de Java. Por ejemplo:

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

Tenga en cuenta que JSON_ARRAYAGG() agrega conjuntos vacíos en NULL , no en un [] vacío . Si eso es un problema, use COALESCE()