我尝试从之前插入的列的值中派生新插入的列的值。例如,如果我有这个数据库,那么每一行(第一行除外)必须引用另一行的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")
}
这可以简单地完成吗?
答案 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)有两种方法:
(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
方法,而不是使用"直接"光滑的陈述。我认为没有办法解决这个问题。