在 Kotlin Exposed 框架中处理子查询

tri*_*ize 3 kotlin kotlin-exposed

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;
Run Code Online (Sandbox Code Playgroud)

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

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()
Run Code Online (Sandbox Code Playgroud)

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

leo*_*idv 6

前面的答案不会在 select 子句中生成子查询。下面描述的方式允许它。这是在Exexped 0.36.2上测试的。

SQL

下一个示例执行 SQL:

SELECT "groups".id, "groups".name,
       (SELECT COUNT(group_members.user_id) FROM group_members 
         WHERE group_members.group_id = "groups".id) members_count
FROM "groups";
Run Code Online (Sandbox Code Playgroud)

如何在 Exexed 中获取它

首先,我们需要一个将 AliasQuery 转换为 Expression 的包装器:

SELECT "groups".id, "groups".name,
       (SELECT COUNT(group_members.user_id) FROM group_members 
         WHERE group_members.group_id = "groups".id) members_count
FROM "groups";
Run Code Online (Sandbox Code Playgroud)

创建子查询:

class SubQueryExpression<T>(private val aliasQuery : QueryAlias) : Expression<T>() {
    override fun toQueryBuilder(queryBuilder: QueryBuilder) {
        aliasQuery.describe(TransactionManager.current(), queryBuilder)
    }
}
Run Code Online (Sandbox Code Playgroud)

将子查询包装到表达式:

val membersCount = GroupMembersTable.userId.count()
val subSelect  = GroupMembersTable
                .slice(membersCount)
                .select { GroupMembersTable.groupId eq GroupsTable.id}
val subQuery: QueryAlias = subSelect.alias("members_count")

Run Code Online (Sandbox Code Playgroud)

进行完整查询:

val membersCountExp = SubQueryExpression<Long>(subQuery)
Run Code Online (Sandbox Code Playgroud)

执行并读取计算值:

val q = GroupsTable
         .slice(GroupsTable.fields + membersCountExp)
         .selectAll()
Run Code Online (Sandbox Code Playgroud)