1

从 groupBy 的“组”部分选择元素的首选方法是什么?(groupBy 导致 [key -> group] 关系)。如果可能的话,它应该会导致一个分贝命中,或者至少是一个恒定数量的命中。

例如,假设我们有一个 Locations(id) 和一个 Companies(id, locationId,foundedDate) 表。我们如何才能找到每个地点最古老的公司?

我会这样做:

Locations.join(Companies).on(_.id === _.locationId).groupBy(_._1).flatMap {
  case (location, companies) =>
    companies.map(_._2).sortBy(_.foundedDate).take(1).map {
      company => (location, company)
    }
}

但这会产生运行时异常:

scala.slick.SlickException: Unsupported query shape containing .groupBy without subsequent .map
at scala.slick.compiler.FuseComprehensions.fuse(Relational.scala:200)
...
4

2 回答 2

1

我不熟悉 Scala 或 Slick,但如果它在后台使用 SQL,这将不起作用。在大多数实现中,查询返回的元素要么需要是类别值之一(在本例中为位置和公司),要么是聚合函数。

这可能有效...

SELECT location.id, company.id, MAX(foundedDate)
FROM companies INNER JOIN locations ON (locations.id = companies.locationId)
GROUP BY location.id, company.id
ORDER BY location.id, MAX(foundedDate)

...但这在功能上等同于进行没有分组的排序:

SELECT location.id, company.id, foundedDate
FROM companies INNER JOIN locations ON (locations.id = companies.locationId)
ORDER BY location.id, foundedDate

要查找最古老的公司而不需要过滤结果,我们可以使用相关子查询:

SELECT location.id, company.id, foundedDate
FROM companies INNER JOIN locations ON (locations.id = companies.locationId)
WHERE foundedDate = (SELECT MAX(foundedDate from companies c2 where c2.locationId = location.id)

如果它们的成立日期相同,这可能会按位置返回多个公司。

我不能说这些如何映射回 Scala/Slick,但希望它会有所帮助。

于 2014-07-12T13:08:46.613 回答
0

Slick 没有为此类查询生成最佳代码,而且如果您在例如 MySQL 中编写此查询,它可能会很重(如果同一地点有几家公司在同一日期成立,则可能会模棱两可)。因此,更简单的解决方案可能是分别选择公司,按位置对它们进行分组并在数据库外按日期排序,然后将它们与位置进行匹配。

val locations = Locations.list.map(location => (l.id,location)).asMap

val lcPairs = Companies.list
                  .group(_.locationId)
                  .map{ case (locationId, companies) => (
                      locations(id),companies.sort(_.foundedDate).head
                   )}
于 2014-07-12T13:03:25.740 回答