【问题标题】:Scala Slick: How to do an except join (left outer join with is null)?Scala Slick:如何进行除连接(左外连接为空)?
【发布时间】:2019-09-02 13:21:24
【问题描述】:

我正在使用 scala 2.11、slick 2.1.0 和 postgres 9.6。大版本升级是不可能的。

我有 2 个相同的表(从同一模型创建),我想做一个除连接(左外连接为空):

我的模型如下所示:

trait Coffee {
  val coffeeLoversId:         Option[Int]
  val taxId:                  Option[Long]
  val internationalCoffeeId:  String
  val providerId:             String
}

class Coffees(tag: Tag, schema: String) extends Table[Coffee](tag, Some(schema), "coffees")

  val coffeeLoversId: Column[Option[Int]] = column[Option[Int]]("coffee_lovers_id")
  val taxId: Column[Option[Long]] = column[Option[Long]]("tax_id")
  val internationalCoffeeId: Column[String] = column[String]("international_coffee_id", O.DBType("VARCHAR"))
  val providerId: Column[String] = column[String]("provider_id", O.DBType("VARCHAR"))

  def * = (coffeeLoversId, taxId, internationalCoffeeId, providerId) <> (Coffee.tupled, Coffee.unapply)

  def ? = (coffeeLoversId, taxId, internationalCoffeeId.?, providerId.?).shaped.<>({r=>import r._; _1.map(_=> Coffee.tupled((_1, _2, _3.get, _4.get)))}, (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))
}


object Coffees {
  def tableQuery(implicit schema: TableSchema) = TableQuery[Coffees]{ tag : Tag => new Coffees(tag, schema.name) }
}

我要运行的 SQL 查询是:

SELECT * from previous.coffees PRV 
LEFT JOIN current.coffees CUR 
ON PRV.international_coffee_id = CUR.international_coffee_id 
WHERE PRV.international_coffee_id IS NULL;

我能做到:

for {
  (c,s) <- Coffees.tableQuery(previousSchema).leftJoin(
    Coffees.tableQuery(currentSchema)
    ) on((x,y) => x.internationalCoffeeId === y.internationalCoffeeId)
} yield(c)

这似乎给了我一个左外连接,但我在过滤空值服务器端时遇到了问题(添加 WHERE PRV.international_coffee_id IS NULL

如有任何建议或想法,我将不胜感激。

【问题讨论】:

    标签: sql postgresql scala slick


    【解决方案1】:

    我能够实现我的目标。首先我尝试使用 scala 的条件理解:

    for {
      (c,s) <- Coffees.tableQuery(previousSchema).leftJoin(
        Coffees.tableQuery(currentSchema)
        ) on((x,y) => x.internationalCoffeeId === y.internationalCoffeeId)
    if(s.internationalCoffeeId.isEmpty)
    } yield(c)
    

    这行得通,并且在数据库上测试我得到了预期的结果,因为我知道我是在 scala 中过滤结果,而不是在数据库服务器上。

    所以我一直在努力,终于到了

    for {
      (c,s) <- Coffees.tableQuery(previousSchema).leftJoin(
        Coffees.tableQuery(currentSchema)
        ) on(
        (x,y) => x.internationalCoffeeId === y.internationalCoffeeId
        ).filter(_._2.internationalCoffeeId.isEmpty)
    } yield(c)
    

    我还不清楚为什么编译器无法正确选择过滤器中匿名函数的输入参数的类型,但我通过直接对元组进行操作来处理它。 我验证了我直接在我的Query(或者在这种情况下是我的CompiledStreamingExecutable)上使用selectStatement 获得了所需的SQL 查询:

    val query = Coffees.tableQuery(previousSchema).leftJoin(
        Coffees.tableQuery(currentSchema)
    ) on(
        (x,y) => x.internationalCoffeeId === y.internationalCoffeeId
    ).filter(_._2.internationalCoffeeId.isEmpty)
    query.selectStatement
    

    【讨论】:

      猜你喜欢
      • 2012-12-31
      • 2013-09-07
      • 1970-01-01
      • 2018-11-05
      • 2012-12-21
      • 1970-01-01
      • 2011-10-01
      • 2015-04-13
      相关资源
      最近更新 更多