在 Scala 中选择 DISTINCT

Posted

技术标签:

【中文标题】在 Scala 中选择 DISTINCT【英文标题】:SELECT DISTINCT in Scala slick 【发布时间】:2013-08-17 21:12:05 【问题描述】:

我使用的是 Slick 1,我必须能够在查询中应用过滤器以查找与相关表中的条件匹配的所有实体。

这个使用 Slick 文档的示例显示了我正在尝试做的事情(这是一个与我的情况接近的人为示例)。

在这里,我想要西海岸供应商提供的所有咖啡。我只想要咖啡,我只对导航到供应商以应用过滤器感兴趣:

val westCoast = Seq("CA", "OR", "WA")
val implicitInnerJoin = for 
  c <- Coffees
  s <- Suppliers if c.supID === s.id && s.state inSet westCoast
 yield c

这没问题,但是如果 Suppliers 表中有多个匹配项,它将复制 Coffees。

明显的解决方法是在普通 SQL 中执行 SELECT DISTINCT;但是,我在这里找不到这样做的方法。

理论上你可以这样做:

query.list.distinct

结果已经返回后;但是,我还实现了 PAGING 支持,因此一旦从数据库中返回结果,您就不想处理结果。这是分页支持:

query.drop(offset).take(limit).list

所以,简而言之,我需要一种方法来在我的查询中指定 SELECT DISTINCT。

有人有什么想法吗?

【问题讨论】:

【参考方案1】:

作为一种解决方法,您可以尝试使用 groupBy:

query.groupBy(x=>x).map(_._1)

它应该具有与 distinct 相同的语义,但我不确定性能。

【讨论】:

嘿,这个成功了!我不确定为什么,我还没有深入研究,但我需要快速修复。 出于某种原因,这给了我一个scala.TupleN 而不是XxxRow 实体,并抛出了ClassCastException【参考方案2】:

使用 slick 3.1.0,您可以使用 distinctdistinctOn 函数 (Slick 3.1.0 release notes)。例如:

val westCoast = Seq("CA", "OR", "WA")
val implicitInnerJoin = for 
  c <- Coffees
  s <- Suppliers if c.supID === s.id && s.state inSet westCoast
 yield c

db.run(implicitInnerJoin.distinctOn(_.name).result)

更新 最后与distinctOn 相关的错误在slick 3.3.3 中得到解决

【讨论】:

FWIW,目前似乎有a bug with distinctOn。【参考方案3】:

我认为这还没有实现。见https://github.com/slick/slick/issues/96

【讨论】:

【参考方案4】:

对于多个列不同的咖啡.名称和咖啡价格:

val westCoast = Seq("CA", "OR", "WA")
val implicitInnerJoin = for 
  c <- Coffees
  s <- Suppliers if c.supID === s.id && s.state inSet westCoast
 yield c

db.run(implicitInnerJoin.map(f => (f.name, f.price, f.state)).distinctOn(p => (p._1, p._2)).result)

【讨论】:

它必须是您描述的特定顺序 - 即map(a =&gt; (a.id, a.name)).disctinctOn(a =&gt; (a._1, a._2)) 或得到slick key not found: s2 运行时异常。做distinctOn(a =&gt; (a.id, a.name)) 是行不通的

以上是关于在 Scala 中选择 DISTINCT的主要内容,如果未能解决你的问题,请参考以下文章

Scala实战

如何在 Scala 中连接两个数据帧并通过索引从数据帧中选择几列?

Scala 中间件选择之间有啥区别?

什么时候在 Scala 中使用 SBT 和 Ivy 模糊地选择了具有相同定义和类路径的两个类?

将在 Gatling Scala 的每个线程中随机选择 csv 中的唯一行

系统学习scala--基础