Scala slick — Как взять значение столбца из разных таблиц

У меня есть 2 таблицы: основная и обновленная с именем столбца, идентификатором и отделом. Я хотел бы сначала прочитать основную таблицу, и если значение поля отдела пусто, я мог бы прочитать его из таблицы обновлений.

Например, из приведенной ниже таблицы я должен получить значение отдела для KING из таблицы обновлений.

Как добиться этого, используя scala slick без выполнения простых запросов sql?

Главная

+-------+----+------------+
+ name  | id | department +            
+-------+----+------------+
| KING  | 10 |            |
| BLAKE | 30 | SALES      |
+-------+----+------------+

Обновить

+-------+----+------------+
+ name  | id | department +  
+-------+----+------------+
| KING  | 10 | SYSTEMS    |
| BLAKE | 30 | SALES      |
+-------+----+------------+

Вот простой sql-запрос

SELECT 
m.`name`,
m.`id`,
if(m.`department`='', u.`department`) as `department`
FROM `Main` m
FROM `Update` u ON m.id=u.id

У меня есть следующий код, определенный до сих пор...

case class Main(name: Option[String],
                id: Option[int],
                department: Option[String])

case class Update(name: Option[String],
                  id: Option[int],
                  department: Option[String])

lazy val mainQuery = TableQuery[MainTableDefinition]
lazy val updateQuery = TableQuery[UpdateTableDefinition]

class MainTableDefinition(tag: Tag) extends Table[Main](tag, "Main") {
      def name = column[Option[String]]("name")
      def id = column[Option[int]]("id")
      def department = column[Option[String]]("department")

      override def * =
         (name, id, department)<> (Main.tupled, Main.unapply)
}

class UpdateTableDefinition(tag: Tag) extends Table[Update](tag, "Update") {
      def name = column[Option[String]]("name")
      def id = column[Option[int]]("id")
      def department = column[Option[String]]("department")

      override def * =
         (name, id, department)<> (Update.tupled, Update.unapply)
}

val query = for {
  m <- mainQuery 
  u <- updateQuery if m.id === u.id
} yield (m, u)

db.run(query.to[List].result)

person Sheshank Kodam    schedule 15.11.2016    source источник
comment
Возможно, вы захотите определить пользовательскую функцию coalesce (postgresql.org/docs/ 9.2/static/functions-conditional.html) и используйте его val query = for { m <- mainQuery u <- updateQuery if m.id === u.id department = coalesce(m.department, u.department) } yield (m.id, department)   -  person Arseniy Zhizhelev    schedule 16.11.2016


Ответы (1)


Прежде всего ваш пример:

SELECT 
m.`name`,
m.`id`,
if(m.`department`='', u.`department`) as `department`
FROM `Main` m
FROM `Update` u ON m.id=u.id

кажется, извлекает комбинацию значений из двух таблиц.

Решение на уровне БД

На уровне БД, возможно, вам подойдет что-то вроде этого:

val query = for {
  m <- mainQuery 
  u <- updateQuery if m.id === u.id
} yield {
  (m.id, m.name, m.department.ifNull(u.department))
}

который, я считаю, очень близок к вашему исходному желаемому запросу (хотя, честно говоря, я не совсем уверен, как ifNull переводится во всех базах данных).

Решение на уровне приложений

На уровне приложения, предполагая, что у вас есть один класс case:

case class NameDepartment(name: Option[String],
                  id: Option[int],
                  department: Option[String])

(кстати, вы можете использовать тип unpacked для обоих определений таблиц, поскольку они идентичны) это может выглядеть так:

  val fetchOperation = (for {
    m <- mainQuery 
    u <- updateQuery if m.id === u.id
  } yield (m, u)
  ).result.map { results => 
    results.map { case (m, u) =>
       NameDepartment(m.name, m.id, m.department.orElse(u.department))
     }
  }
person Paul Dolega    schedule 30.11.2016
comment
Спасибо. Я попробую это и дам вам знать. - person Sheshank Kodam; 04.12.2016
comment
Нельзя с уверенностью сказать, что это сработало. Использование карт несколько раз сбивало с толку. - person Sheshank Kodam; 09.12.2016
comment
Я полагаю, вы пробовали только вторую версию? Вы проверили первый вариант? Тот, который обозначен: На ​​уровне БД, возможно, что-то вроде этого сработает для вас ‹- у него нет нескольких карт. Также что сказать Не могу ... сказать, что это сработало? Вас смутило несколько карт (во втором примере), но он делает то, что вам нужно, или не работает (компилирует или возвращает результаты, которых вы хотели достичь)? Просто любопытно. РЕДАКТИРОВАТЬ: в мой ответ добавлены разделы, чтобы четко указать, что там есть два решения. - person Paul Dolega; 09.12.2016
comment
На самом деле мне пришлось перепроектировать архитектуру, и у меня есть еще один вопрос, похожий на этот. Однако я пробовал это с моими данными, и ваше решение работает. Спасибо за помощь. Принял ваш ответ. - person Sheshank Kodam; 11.12.2016