使用Slick筛选选择

时间:2019-08-06 09:20:55

标签: sql scala slick

如何在Slick中执行以下sql语句。问题是在select语句中有过滤器,我不知道如何在Slick中进行过滤。

SELECT Sellers.ID,
       COALESCE(count(DISTINCT Produce.IMPORTERID) FILTER (WHERE Produce.CREATED > '2019-04-30 16:38:00'), 0::int) AS AFTERDATE,
       COALESCE(count(DISTINCT Produce.IMPORTERID) FILTER (WHERE Produce.NAME::text = 'Apple'::text AND Produce.CREATED > '2018-01-30 16:38:00'), 0::bigint) AS APPLES
FROM Sellers
JOIN Produce ON Produce.SellersID = Sellers.ID
WHERE Sellers.ID = 276
GROUP BY Sellers.ID;

2 个答案:

答案 0 :(得分:0)

尝试

import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import slick.jdbc.PostgresProfile.api._

case class Seller(id: Long)
case class Produce(name: String, sellerId: Long, importerId: Long, created: LocalDateTime)

class Sellers(tag: Tag) extends Table[Seller](tag, "Sellers") {
  def id = column[Long]("ID", O.PrimaryKey)
  def * = id <> (Seller.apply, Seller.unapply)
}

class Produces(tag: Tag) extends Table[Produce](tag, "Produce") {
  def name = column[String]("NAME", O.PrimaryKey)
  def sellerId = column[Long]("SellersID")
  def importerId = column[Long]("IMPORTERID")
  def created = column[LocalDateTime]("CREATED")
  def * = (name, sellerId, importerId, created) <> (Produce.tupled, Produce.unapply)
}

val sellers = TableQuery[Sellers]
val produces = TableQuery[Produces]

val dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
val ldt2019 = LocalDateTime.parse("2019-04-30 16:38:00", dtf)
val ldt2018 = LocalDateTime.parse("2018-01-30 16:38:00", dtf)

sellers.join(produces).on(_.id === _.sellerId)
  .filter { case (s, p) => p.sellerId === 276L }
  .groupBy { case (s, p) => s.id }
  .map { case (sid, group) =>
  (
    sid,
    group
      .filter { case (s, p) => p.created > ldt2019 }
      .map { case (s, p) => p.importerId }
      .distinct.length,
    group
      .filter { case (s, p) => p.name === "Apple" && p.created > ldt2018 }
      .map { case (s, p) => p.importerId }
      .distinct.length
  )
}

libraryDependencies += "com.github.tminglei" %% "slick-pg" % "0.18.0"

答案 1 :(得分:0)

我真的希望像@Dymytro的答案一样有效,但是从我的测试来看,一切都归结于GROUP BY的局限性,这是您将遇到的问题:

  1. 尝试仅将Slick与Postgres驱动程序配合使用将不起作用,因为Slick不支持带有FILTER子句的聚合函数。 Postgres是少数支持FILTER的数据库之一!所以你不会走得太远:
someQuery
    .groupBy { a => a.pivot  }
      .map{ case (pivot, query) =>
        (
          pivot,
          query
            .filter(_.condition === "stuff")
            .map(_.column).distinct.length
        )
      }

尽管可以编译,但您会遇到类似以下的运行时错误:

  

[错误] slick.SlickTreeException:无法将节点转换为SQL理解

  1. 然后,如果您签出slick-pg,就会发现它支持Postgres聚合函数!包括FILTER子句!但是... aggregate functions with GROUP BY有一个未解决的问题,因此这种尝试也将失败:
import com.github.tminglei.slickpg.agg.PgAggFuncSupport.GeneralAggFunctions._

...

someQuery
    .groupBy { a => a.pivot  }
    .map{ case (pivot, query) =>
        (
          pivot,
          query
              .map(a => count(a.column.distinct).filter(a.condition === "stuff"))
        )
      }
  

未找到匹配的形状。   [错误] Slick不知道如何映射给定的类型。

因此,幸运的是,简单的单列 FILTER expressions can be equivalently implemented with the more primitive CASE statements解决了这些问题或有人发布了解决方法。虽然不那么漂亮,但是可以正常工作!

val caseApproach = someQuery
    .groupBy { a => a.pivot  }
    .map{ case (pivot, query) =>
        (
          pivot,
          query
              .map{ a =>
                Case If a.condition === "stuff" Then a.column
              }.min //here's where you add the aggregate, e.g. "min"
        )
      }

println(caseApproach.result.statements.headOption)
  

从数据透视表组中依次选择数据透视表min(((((condition)='stuff')然后是“ column” end)时的情况)