简体   繁体   中英

jooq multiset order result set via conditions on multiset

Gathering the first experience mit jooq's multiset I try to figure out how to order the result set based on some criteria for the multiset. Consider a datastructure with a Product Table and each product can be assigned an arbitrary amount of storages.

When fetching products with this query:

  List<ProductFilterItem> items =
        dslContext
            .select(
                PRODUCT.ID,
                PRODUCT.NAME
                multiset(
                    select(
                        PRODUCT_STORAGE.ID,
                        PRODUCT_STORAGE.PRODUCT_ID,
                        PRODUCT_STORAGE.STOCK
                        PRODUCT_STORAGE.MIN_STOCK
                    )
                        .from(PRODUCT_STORAGE)
                        .where(PRODUCT_STORAGE.PRODUCT_ID.eq(PRODUCT.ID))
                ).as("storage").convertFrom(r -> r.into(ProductStorageItem.class))
            )
            .from(PRODUCT)
            .where(queryCondition)
            .fetchInto(ProductItem.class)

how to order the results based on criteria for the multiset.

Eg put those first that have a storages assigned.

orderBy(inline(3).desc())

gives the desired result, but to me it is not clear what the actual sort comparison is doing.

How to achieve more complex sorting, eg order by

min(
(PRODUCT_STORAGE.STOCK - PRODUCT_STORAGE.MIN_STOCK)
  .divide(PRODUCT_STORAGE.MIN_STOCK.multiply(0.01))
)

or other computations based on stock values.

Thanks for your help!

Kind Regards, Andreas

Relying on MULTISET ordering

As of jOOQ 3.15, MULTISET are emulated in all dialects using either SQL/XML or SQL/JSON. While the order of XML documents is undefined, some SQL dialects may choose to define an order on JSON documents (eg PostgreSQL does it for JSONB ). But I'm not convinced it's a good idea in your case to depend on this implicit ordering (specifically, because jOOQ's emulations might change subtly to adapt to some edge cases), so better be explicit about what you want.

In standard SQL, you could extract data from your MULTISET nested collection again in order to find some aggregate value like your MIN(...) expression, but that seems quite laborious, and is currently not supported by jOOQ 3.15 (there are some standard SQL operators to operate on multisets, see https://github.com/jOOQ/jOOQ/issues/12031 )

MULTISET_AGG alternative

Since you want to order things by some aggregate value, why not use MULTISET_AGG instead of MULTISET ? In the following case, you get an equivalent result, and ordering is well defined.

List<ProductFilterItem> items = dslContext
    .select(
        PRODUCT.ID,
        PRODUCT.NAME
        multisetAgg(
            PRODUCT_STORAGE.ID,
            PRODUCT_STORAGE.PRODUCT_ID,
            PRODUCT_STORAGE.STOCK
            PRODUCT_STORAGE.MIN_STOCK
        ).as("storage").convertFrom(r -> r.into(ProductStorageItem.class))
    )
    .from(PRODUCT)
    .leftJoin(PRODUCT_STORAGE)
        .on(PRODUCT_STORAGE.PRODUCT_ID.eq(PRODUCT.ID))
    .where(queryCondition)
    .groupBy(PRODUCT.ID, PRODUCT.NAME)
    .orderBy(min(
        PRODUCT_STORAGE.STOCK
            .minus(PRODUCT_STORAGE.MIN_STOCK)
            .divide(PRODUCT_STORAGE.MIN_STOCK.multiply(0.01))
    ))
    .fetchInto(ProductItem.class)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM