Med JOIN
fungerar inte för detta.
Din fråga kommer att vara ganska ineffektiv eftersom om du använder joins på det här sättet skapar du en kartesisk produkt mellan böckerna och artikeltabellen, vilket resulterar i en hel del minnes- och CPU-förbrukning både i databasen och i din Java-klient, innan du deduplicerar alla meningslösa kombinationer.
Den "korrekta" SQL-metoden skulle vara att använda MULTISET
som beskrivs i den här artikeln här
. Tyvärr har jOOQ 3.9 inte stöd för MULTISET
ännu
(inte många databaser). Så du bör skapa två separata frågor:
- Hämtar alla böcker
- Hämtar alla artiklar
Och använd sedan något som Java 8 Streams för att mappa dem till ett enda objekt.
Med MULTISET
från och med jOOQ 3.15
Lyckligtvis, från och med jOOQ 3.15, finns det en färdig lösning för att kapsla samlingar i SQL med MULTISET
. Din fråga skulle se ut så här:
Använda reflektion
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);
Använd typ säker, annons -hoc-konvertering
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));
För mer information om MULTISET
, se detta blogginlägg
, eller de manuella avsnitten:
Använder SQL/XML eller SQL/JSON från och med jOOQ 3.14
Från och med jOOQ 3.14 kan du kapsla samlingar via SQL/XML eller SQL/JSON, om din RDBMS stödjer det. Du kan skapa ett dokument och sedan använda något som Gson, Jackson eller JAXB för att mappa tillbaka det till dina Java-klasser. Till exempel:
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);
Observera att JSON_ARRAYAGG()
aggregerar tomma uppsättningar till NULL
, inte i en tom []
. Om det är ett problem, använd COALESCE()