Scala Slick: Как сделать соединение, кроме соединения (левое внешнее соединение со значением null)? - PullRequest
0 голосов
/ 11 апреля 2019

Я использую scala 2.11, slick 2.1.0 и postgres 9.6.Об обновлении основной версии не может быть и речи.

У меня есть 2 идентичные таблицы (созданные из той же модели), и я хочу сделать исключающее соединение (левое внешнее соединение с нулем): except join

Моя модель выглядит следующим образом:

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;

Я смог пройти так далекоas:

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)

Я буду благодарендля любых указателей или идей.

1 Ответ

1 голос
/ 12 апреля 2019

Мне удалось достичь своей цели.Сначала я попытался использовать условное понимание 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)

Пока не ясно, почему компилятор не может правильно подобрать тип типа входного параметра дляанонимная функция в моем фильтре, но я справился с ней, работая непосредственно с кортежем.Я подтвердил, что получаю нужный SQL-запрос, используя selectStatement непосредственно на моем Query (или в этом случае на моем CompiledStreamingExecutable):

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