Написать запрос на объединение с groupby в Scala ActiveRecord - PullRequest
7 голосов
/ 04 апреля 2019

Я пытаюсь написать конкретный запрос в scala Active record . Но это всегда ничего не возвращает. Я прочитал вики на странице GitHub, но она не содержит много информации о ней. Я пытаюсь написать запрос

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

Я попробовал

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)

Но сначала возвращаемый тип становится картой, а не списком. И, во-вторых, при выполнении он ничего не возвращает, даже если данные существуют. При выполнении запроса SQL непосредственно к базе данных ожидаемые результаты возвращаются.

1 Ответ

4 голосов
/ 13 апреля 2019

scala-activerecord dsl основан на squeryl, поэтому при вычислении сложного запроса мы могли бы опуститься до низкого уровня и использовать его statement для красивой печатиSQL-утверждение.Таким образом, мы могли бы итеративно настраивать dsl, пока не получим требуемый оператор SQL.Например, скажем, у нас есть следующая схема:

object Tables extends ActiveRecordTables {
  val persons = table[Person]
  val tickets = table[Ticket]
}

case class Person(name: String, email: String, age: Int) extends ActiveRecord
case class Ticket(price: Float, priority: Boolean) extends ActiveRecord {
  lazy val person = belongsTo[Person]
}

object Person extends ActiveRecordCompanion[Person]
object Ticket extends ActiveRecordCompanion[Ticket]

, и мы переходим к squeryl dsl, чтобы определить следующий запрос

  val query =
    dsl.join(Person.toQuery, Ticket.toQuery)((person, ticket) =>
      groupBy(person.name, person.age)
      compute(count(ticket.id))
      on(person.id === ticket.id)
    )

, тогда мы можем довольно просто напечатать оператор, используя

println(Person.inTransaction(query.statement))

, который выводит реальный оператор SQL

Select
  q1.people6_name as g0,
  q1.people6_age as g1,
  count(q7.tickets11_id) as c0
From
(Select
   people6.name as people6_name,
   people6.email as people6_email,
   people6.age as people6_age,
   people6.id as people6_id
 From
   people people6
)  q1
 inner join (Select
   tickets11.priority as tickets11_priority,
   tickets11.price as tickets11_price,
   tickets11.id as tickets11_id
 From
   tickets tickets11
)  as q7 on (q1.people6_id = q7.tickets11_id)
Group By
  q1.people6_name,
  q1.people6_age

Как только мы выясним правильный dsl в squeryl, мы по крайней мере узнаем, что это возможно, и затем мы могли бы попытаться написать его также в scala-activerecord.Потенциальным преимуществом этого подхода является то, что у Странно больше документации.Обратите внимание на то, что говорится в Групповых и агрегированных запросах , что должно косвенно также выполняться для scala-activerecord:

Squeryl немного отличается от SQL в том смысле, что агрегатные функции не разрешеныв пределах выбора .Вместо этого они объявляются в предложении 'compute', которое фактически является скрытым выбором, поскольку его аргументы заканчиваются в предложении select сгенерированного SQL.Мотивация для этого выбора дизайна состоит в том, чтобы немного усложнить написание недействительных операторов Select, поскольку DSL заставляет предложение 'compute' заменять выбор или следовать за groupBy.

Насколько я понимаю, это означает, что мы не должны писать PassTicket.where(_.passId === pass.id).count в предложении select.

Относительно groupBy, возвращающего Map, мы могли бы вызвать values.toList, чтобы получитьобратно список, например, скажем, у нас есть

  Person("Picard", "picard@starfleet.org", 34).save
  Person("Data", "data@starfleet.org", 40).save
  Person("Geordi", "geordi@starfleet.org", 40).save

тогда println(Person.groupBy(person => person.age).values.toList) должно дать

List(
  List(Person(Data,data@starfleet.org,40), Person(Geordi,geordi@starfleet.org,40)), 
  List(Person(Picard,picard@starfleet.org,34))
)
...