Write join query with groupby in Scala ActiveRecord

Adr*_*zin 7 activerecord scala join group-by

I am trying to write a specific query in scala Active record. But it always returns nothing. I have read the wiki on the github page but it does not contain a lot of info on it. The query I am trying to write is

SELECT e.name, e.id, COUNT(pt.pass_id) as pass_count, e.start_date, e.total_passes_to_offer
FROM events e inner join passes p on e.id = p.event_id inner join pass_tickets pt on p.id = pt.pass_id where e.partner_id = 198 group by e.name, e.id
Run Code Online (Sandbox Code Playgroud)

What I have tried is

Event.joins[Pass, PassTicket](
                (event, pass, passTicket) => (event.id === pass.eventId, pass.id === passTicket.passId)
            ).where(
                (event, _, _) => event.partnerId === partnerId
            ).select(
                (event, pass, _) => (event.name, event.id, PassTicket.where(_.passId === pass.id).count, event.startDate, event.totalPassesToOffer)
            ).groupBy( data => data._2)
Run Code Online (Sandbox Code Playgroud)

But first, the return type becomes a map, not a list. And second when executed, it doesnt return anything even though the data exists. When running the SQL query directly against the database, the expected results return.

Mar*_*lic 4

scala-activerecorddsl 基于squeryl,因此当计算出复杂的查询时,我们可以下降到 squeryl 级别并使用其statement功能来漂亮地打印 SQL 语句。这样我们就可以迭代地调整 dsl,直到获得所需的 SQL 语句。例如,假设我们有以下模式:

\n\n
object Tables extends ActiveRecordTables {\n  val persons = table[Person]\n  val tickets = table[Ticket]\n}\n\ncase class Person(name: String, email: String, age: Int) extends ActiveRecord\ncase class Ticket(price: Float, priority: Boolean) extends ActiveRecord {\n  lazy val person = belongsTo[Person]\n}\n\nobject Person extends ActiveRecordCompanion[Person]\nobject Ticket extends ActiveRecordCompanion[Ticket]\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后我们转到 squeryl dsl 来定义以下查询

\n\n
  val query =\n    dsl.join(Person.toQuery, Ticket.toQuery)((person, ticket) =>\n      groupBy(person.name, person.age)\n      compute(count(ticket.id))\n      on(person.id === ticket.id)\n    )\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后我们可以使用以下命令漂亮地打印语句

\n\n
println(Person.inTransaction(query.statement))\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出实际的 SQL 语句

\n\n
Select\n  q1.people6_name as g0,\n  q1.people6_age as g1,\n  count(q7.tickets11_id) as c0\nFrom\n(Select\n   people6.name as people6_name,\n   people6.email as people6_email,\n   people6.age as people6_age,\n   people6.id as people6_id\n From\n   people people6\n)  q1\n inner join (Select\n   tickets11.priority as tickets11_priority,\n   tickets11.price as tickets11_price,\n   tickets11.id as tickets11_id\n From\n   tickets tickets11\n)  as q7 on (q1.people6_id = q7.tickets11_id)\nGroup By\n  q1.people6_name,\n  q1.people6_age\n
Run Code Online (Sandbox Code Playgroud)\n\n

一旦我们在 squeryl 中找出正确的 dsl,那么我们至少知道它是可能的,然后我们可以尝试将它也写入 scala-activerecord 中。这种方法的潜在优势是 squirly 似乎有更多文档。请注意它在“组查询”和“聚合查询”上的说明,这也应该间接适用于 scala-activerecord:

\n\n
\n

Squeryl 与 SQL 略有不同,因为select 中不允许使用聚合函数。相反,它们是在 \xe2\x80\x98compute\xe2\x80\x99\n 子句中声明的,这实际上是一个变相的选择,因为它\xe2\x80\x99s 参数最终\n 出现在生成的 SQL\xe2\ 中。 x80\x99s 选择子句。这种设计选择的动机是让编写无效的 Select 语句变得更加困难,因为 DSL强制使用 \xe2\x80\x98compute\xe2\x80\x99 子句来替换\na select 或跟随一个groupBy。

\n
\n\n

根据我的理解,这意味着我们不应该PassTicket.where(_.passId === pass.id).countselect子句中写入。

\n\n

关于groupBy返回 a Map,我们可以调用values.toList它来获取列表,例如,假设我们有

\n\n
  Person("Picard", "picard@starfleet.org", 34).save\n  Person("Data", "data@starfleet.org", 40).save\n  Person("Geordi", "geordi@starfleet.org", 40).save\n
Run Code Online (Sandbox Code Playgroud)\n\n

那么println(Person.groupBy(person => person.age).values.toList)应该给

\n\n
List(\n  List(Person(Data,data@starfleet.org,40), Person(Geordi,geordi@starfleet.org,40)), \n  List(Person(Picard,picard@starfleet.org,34))\n)\n
Run Code Online (Sandbox Code Playgroud)\n