使用 slick 创建 table 视图

Creating table view using slick

如何使用 slick 3 为 postgresql view 创建查询?

我没有在华而不实的文档中找到答案。

这个问题与我的另一个有关。我得到了正确的答案,但我不知道如何使用 slick 来实现它。

Slick 3 中仅对视图提供基本支持,不能保证完整的编译时安全性和组合性,考虑到大多数视图强烈依赖于其他 table 中的数据,后者尤其重要。 您可以将视图描述为 Table 和单独的模式操作语句,您 必须 使用它而不是标准的 table 模式扩展方法,如创建和删除。这是 的示例,受 REGISTRY 和 ROWS table 已经存在于数据库中:

case class RegRn(id: Int, name: String, count: Long)

trait View{
  val viewName = "REG_RN"
  val registryTableName = "REGISTRY"
  val rowsTableName = "ROWS"

  val profile: JdbcProfile
  import profile.api._

  class RegRns(tag: Tag) extends Table[RegRn](tag, viewName) {

    def id    = column[Int]   ("REGISTRY_ID")
    def name  = column[String]("NAME", O.SqlType("VARCHAR"))
    def count = column[Long]  ("CT", O.SqlType("VARCHAR"))

    override def * = (id, name, count) <> (RegRn.tupled, RegRn.unapply)
    ...
  }

  val regRns = TableQuery[RegRns]
  val createViewSchema = sqlu"""CREATE VIEW #$viewName AS
                                   SELECT R.*, COALESCE(N.ct, 0) AS CT
                                   FROM   #$registryTableName R
                                   LEFT   JOIN (
                                     SELECT REGISTRY_ID, count(*) AS CT
                                     FROM   #$rowsTableName
                                     GROUP  BY REGISTRY_ID
                                   ) N ON R.REGISTRY_ID=N.REGISTRY_ID"""

  val dropViewSchema = sqlu"DROP VIEW #$viewName"
  ...
}

您现在可以使用 db.run(createViewSchema) 创建视图,使用 db.run(dropViewSchema) 删除它,当然调用 MTable.getTables("REG_RN") 可以预期地找到它的 tableType 是 "VIEW".查询与其他 tables 相同,例如 db run regRns.result.head。如果规则允许,您甚至可以像对普通 Slick table 所做的那样将值插入视图(由于 COALESCE 和子查询,这不是您的情况)。 正如我提到的,当您想组合现有的 Table 来创建视图时,一切都会变得一团糟。您将必须始终保持它们的名称和定义同步,因为现在不可能编写任何至少可以保证视图的形状符合基础 table 的组合形状的东西。好吧,除了这样丑的没办法:

trait View{
  val profile: JdbcProfile
  import profile.api._

  val registryTableName = "REGISTRY"
  val registryId   = "REGISTRY_ID"
  val regitsryName = "NAME"

  class Registries(tag: Tag) extends Table[Registry](tag, registryTableName) {

    def id   = column[Int]   (registryId)
    def name = column[String](regitsryName, O.SqlType("VARCHAR"))

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

  val rowsTableName = "ROWS"
  val rowsId  = "ROW_ID"
  val rowsRow = "ROW"

  class Rows(tag: Tag) extends Table[Row](tag, rowsTableName) {

    def id  = column[String](rowsId, O.SqlType("VARCHAR"))
    def rid = column[Int]   (registryId)
    def r   = column[String]("rowsRow", O.SqlType("VARCHAR"))

    override def * = (id, rid, r) <> (Row.tupled, Row.unapply)
    ...
  }

  val viewName = "REG_RN"

  class RegRns(tag: Tag) extends Table[RegRn](tag, viewName) {

    def id    = column[Int]   ("REGISTRY_ID")
    def name  = column[String]("NAME", O.SqlType("VARCHAR"))
    def count = column[Long]  ("CT", O.SqlType("VARCHAR"))

    override def * = (id, name, count) <> (RegRn.tupled, RegRn.unapply)
    ...
  }

  val registries = TableQuery[Registries]
  val rows = TableQuery[Rows]
  val regRns = TableQuery[RegRns]
  val createViewSchema = sqlu"""CREATE VIEW #$viewName AS
                                       SELECT R.*, COALESCE(N.ct, 0) AS CT
                                       FROM   #$registryTableName R
                                       LEFT   JOIN (
                                         SELECT #$registryId, count(*) AS CT
                                         FROM   #$rowsTableName
                                         GROUP  BY #$registryId
                                       ) N ON R.#$registryId=N.#$registryId"""

  val dropViewSchema = sqlu"DROP VIEW #$viewName"
  ...
}

如何在视图序言后附加查询文本:

val yourAwesomeQryComposition : TableQuery = ...

val qryText = yourAwesomeQryComposition.map(reg => (reg.id, ....)).result.statements.head

val createViewSchema = sqlu"""CREATE VIEW #$viewName AS #${qryText}"""