如何在涉及 group by、having、count 的 slick 中表达此查询
How to express this query in slick involving group by, having, count
假设我在 Slick 3.2.3 中有一个这样定义的 table:
class ATable(tag: Tag) extends Table[(Int, Option[Boolean])](tag, "a_table") {
def someInt = column[Int]("some_int")
def someBool = column[Option[Boolean]]("some_bool")
def * = (someInt, someBool)
}
object ATable extends TableQuery(new ATable(_))
还有一些数据:
insert into a_table
values
(1, true),
(2, null),
(2, true),
(2, null),
(3, true),
(3, true),
(3, null);
现在我想在 table 中找到那些整数,其中只有一行 some_bool
不是 null
。这在SQL中并不难:
select some_int
from a_table
group by some_int
having count(some_bool) = 1;
这很好用。那么让我们用 Slick 试试吧:
ATable
.groupBy(_.someInt)
.filter(_._2.map(_.someBool).countDefined === 1)
.map(_._1)
编译时,它会在运行时崩溃并显示错误消息“slick.SlickTreeException: Cannot convert node to SQL Comprehension
”。这是一个已知的限制还是 slick 中的错误?或者我应该以不同的方式编写查询吗?
当然可以用子查询来写这个,但我更愿意理解为什么 groupBy
东西不起作用…
您的 SQL 的 Slick
-等价物应该类似于以下示例中的 query
:
val aTable: TableQuery[ATable] = TableQuery[ATable]
val setupAction: DBIO[Unit] = DBIO.seq(
aTable.schema.create,
aTable += (1, Some(true)),
aTable += (2, None),
aTable += (2, Some(true)),
aTable += (2, None),
aTable += (3, Some(true)),
aTable += (3, Some(true)),
aTable += (3, None)
)
val setupFuture: Future[Unit] = db.run(setupAction)
val f = setupFuture.flatMap{ _ =>
val query =
aTable.groupBy(_.someInt).
map{ case (someInt, group) => (someInt, group.map(_.someBool).countDefined) }.
filter(_._2 === 1).
map(_._1)
println("Generated SQL for query:\n" + query.result.statements)
db.run(query.result.map(println))
}
// Generated SQL for query:
// List(select "some_int" from "a_table" group by "some_int" having count("some_bool") = 1)
// Vector(1, 2)
假设我在 Slick 3.2.3 中有一个这样定义的 table:
class ATable(tag: Tag) extends Table[(Int, Option[Boolean])](tag, "a_table") {
def someInt = column[Int]("some_int")
def someBool = column[Option[Boolean]]("some_bool")
def * = (someInt, someBool)
}
object ATable extends TableQuery(new ATable(_))
还有一些数据:
insert into a_table
values
(1, true),
(2, null),
(2, true),
(2, null),
(3, true),
(3, true),
(3, null);
现在我想在 table 中找到那些整数,其中只有一行 some_bool
不是 null
。这在SQL中并不难:
select some_int
from a_table
group by some_int
having count(some_bool) = 1;
这很好用。那么让我们用 Slick 试试吧:
ATable
.groupBy(_.someInt)
.filter(_._2.map(_.someBool).countDefined === 1)
.map(_._1)
编译时,它会在运行时崩溃并显示错误消息“slick.SlickTreeException: Cannot convert node to SQL Comprehension
”。这是一个已知的限制还是 slick 中的错误?或者我应该以不同的方式编写查询吗?
当然可以用子查询来写这个,但我更愿意理解为什么 groupBy
东西不起作用…
您的 SQL 的 Slick
-等价物应该类似于以下示例中的 query
:
val aTable: TableQuery[ATable] = TableQuery[ATable]
val setupAction: DBIO[Unit] = DBIO.seq(
aTable.schema.create,
aTable += (1, Some(true)),
aTable += (2, None),
aTable += (2, Some(true)),
aTable += (2, None),
aTable += (3, Some(true)),
aTable += (3, Some(true)),
aTable += (3, None)
)
val setupFuture: Future[Unit] = db.run(setupAction)
val f = setupFuture.flatMap{ _ =>
val query =
aTable.groupBy(_.someInt).
map{ case (someInt, group) => (someInt, group.map(_.someBool).countDefined) }.
filter(_._2 === 1).
map(_._1)
println("Generated SQL for query:\n" + query.result.statements)
db.run(query.result.map(println))
}
// Generated SQL for query:
// List(select "some_int" from "a_table" group by "some_int" having count("some_bool") = 1)
// Vector(1, 2)