从另一行的列值Slick中导出列值

时间:2016-09-22 00:42:18

标签: scala slick slick-3.0

我尝试从之前插入的列的值中派生新插入的列的值。例如,如果我有这个数据库,那么每一行(第一行除外)必须引用另一行的ID。我想在Height引用

行的Height值中将Previous ID列加1
----------
ID | Previous ID | Height

0  | null        | 123   

1  | 0           | 124 

2  | 1           | 125 

3  | 1           | 125

请注意height如何使用主键height从之前的ID值增加1。有没有简单的方法用Slick做到这一点?表格看起来像这样

case class ExampleCaseClass(id: Option[Long], previousId: Long)

class ExampleTable(tag: Tag)  extends Table[ExampleCaseClass](tag,"example") { 

def id = column[Long]("id",O.PrimaryKey, O.AutoInc) 

def previousId = column[Long]("previous_id")

//this is the column that needs to be derived based on the height of 'previousId'
def height = column[Long]("height") 

}

这可以简单地完成吗?

2 个答案:

答案 0 :(得分:1)

如果您不想公开height字段,可以使用普通的SQL查询来执行此操作:

def insertExample(previousId: Int): DBIO[Int] = {
  sqlu"insert into example (previous_id, height) select $previousId, height + 1 from example where id = $previousId"
}

实现此功能的另一种方法是添加数据库触发器。通过这种方式,您可以使用普通插入,数据库将执行自动增量:

CREATE TRIGGER auto_height BEFORE INSERT ON example
FOR EACH ROW
SET NEW.height = 1 + (SELECT height FROM example WHERE id = NEW.previous_id);

答案 1 :(得分:0)

这有两个部分:

  1. 如何使用依赖于其他行的值插入行?
  2. 如何以逻辑“透明”的方式打包它?对你桌子的用户?
  3. (1)有两种方法:

    • (1a)在单独的SQL语句中执行查询和插入,并对数据库进行两次往返。 (几乎在所有情况下都表现良好。)

    • (1b)执行查询并使用INSERT INTO ... SELECT语句插入一个SQL语句。 (在某些不常见的情况下,速度更快)。

    除了表现之外,这两者需要不同的句法方法。 Slick中的两种方法都在以下两个答案中讨论:

    Scala+Slick 3: Inserting the result of one query into another table

    我实际上认为(1b)无论如何都更简洁。我提到(1a)给你另一个探索的选择。 (1b)使用forceInsertQuery完成,如下所述:

    http://slick.lightbend.com/doc/3.1.1/queries.html#inserting

    val example = TableQuery[ExampleTable]
    def insertAuto(previousId: Int) = {
      val query = example.filter(_.id == previousId).map(r => (previousId, r.height))
      DBIO.seq(example.forceInsertQuery(query))
    }
    

    (请注意,使用INSERT INTO .. SELECT时,只需将文字嵌入SELECT子句中,即可将用户提供的文字值与查询值混合。)

    可能存在我们需要提供ID的问题,即使它已自动递增,因为文档似乎建议forceInsertQuery需要显式值,即使对于autoinc列也是如此。

    现在,您希望如何打包该def以方便用户调用,我实际上并不确定。这应该是一个更简单的事情。您可以考虑在TableQuery[ExampleTable]上将其作为扩展方法:

    implicit class RichExampleTable(example: TableQuery[ExampleTable]) {
      // def extension methods here
    }
    

    但这确实要求您的用户调用insertAuto方法,而不是使用"直接"光滑的陈述。我认为没有办法解决这个问题。