在Kotlin暴露框架中处理子查询

问题描述

Exposed 0.27.1是否可以翻译以下sql语句?

SELECT FirstName,LastName,(SELECT COUNT(O.Id)
    FROM "Order" O
    WHERE O.CustomerId = C.Id) AS OrderCount
FROM Customer C;

这是我尝试过的方法,但不幸的是,子查询独立于其余查询工作。

val query = Customer
    .leftJoin(Order,{ Customer.id },{ Order.customerId })
    .slice(
            Customer.firstName,Customer.lastName,intLiteral(Order
                    .innerJoin(Customer,{ Order.customerId },{ Customer.id })
                    .slice(Order.id.count())
                    .select { Order.customerId eq Customer.id }
                    .first()[Order.id.count()].toInt())//.alias("OrderCount")
    )
    .selectAll()

此外,如果有可能,那么我如何使用别名从ResultRow中获取结果?在this example之后,解决方案似乎是将带有alias()方法调用的整个子查询存储在单个变量中,但这看起来很难看。有更好的方法吗?

解决方法

正式F.A.Q.指出拥有子查询的唯一方法是via alias for inner query

val orderCount = Order.customerId.count().alias("OrderCount")
val subQuery = Order.slice(Order.customerId,orderCount)
                    .selectAll()
                    .groupBy(Order.customerId)
                    .alias("subQuery")
val query = Join(Customer)
                    .join(subQuery,JoinType.LEFT,subQuery[Order.customerId],Customer.id)
                    .slice(Customer.firstName,Customer.lastName,subQuery[orderCount])
                    .selectAll()

但是,也许您在这里不需要子查询?此查询生成的SQL查询略有不同,查询结果几乎相同(与前一个查询相反,如果没有客户订单,它将返回0而不是null):

val query = Customer
            .leftJoin(Order,{ Customer.id },{ Order.customerId })
            .slice(Customer.firstName,Order.id.count().alias("OrderCount"))
            .selectAll()
            .groupBy(Customer.id)

生成的SQL:

SELECT CUSTOMER."firstName",CUSTOMER."lastName",COUNT("ORDER".ID) OrderCount
FROM CUSTOMER
LEFT JOIN "ORDER" ON CUSTOMER.ID = "ORDER"."customerId"
GROUP BY CUSTOMER.ID
,

谢谢,这个方法很有效,尽管第一个解决方案很难理解,并且对使用的逻辑进行了一些文字上的解释。

我设法从中提取数据

assertEquals("Manuel",query.andWhere { subQuery[orderCount] eq intLiteral(2) }.first()[Customer.firstName])

但是我无法从第二个解决方案中提取数据。这是我所做的:

val orderCount = Order.id.count().alias("OrderCount")

val query = Customer
    .leftJoin(Order,{ Order.customerId })
    .slice(Customer.firstName,orderCount)
    .selectAll()
    .groupBy(Customer.id)

assertEquals("Manuel",query.andWhere { orderCount eq intLiteral(2) }.first()[Customer.firstName])