gpt4 book ai didi

sql - 在 Slick 3.0 中结合分页和非查询分组的好方法是什么?

转载 作者:行者123 更新时间:2023-12-04 21:38:40 25 4
gpt4 key购买 nike

为简单起见,假设我有三个表:

val postTable = TableQuery[Posts]
val postTagTable = TableQuery[PostTags]
val tagTable = TableQuery[Tags]

一篇文章可以有多个标签和 postTagTable只包含关系。

现在我可以像这样查询帖子和标签:
val query = for {
post <- postTable
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)

val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}

这会给我一个 Future[Seq[(Post, Seq(Tag))]] .

到现在为止还挺好。

但是如果我想为帖子添加分页怎么办?
自一个 Post可以有多个 Tags通过上面的查询,我不知道 take 有多少行从查询中,为了得到,比方说, 10 Posts .

有没有人知道在单个查询中使用特定数量的帖子获得相同结果的好方法?

实际上,我什至不确定如何在没有嵌套查询的 native SQL 中处理这个问题,所以如果有人在那个方向有建议,我也会很高兴听到它。

谢谢!

编辑

让你知道,我目前正在做什么样的查询:
val pageQuery = postTable drop(page * pageSize) take(pageSize)

val query = for {
pagePost <- pageQuery
post <- postTable if pagePost.id === post.id
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)

val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}

但这显然会导致嵌套查询。而这正是我想要避免的。

编辑 2

另一种可能的 2-query 解决方案:
val pageQuery = postTable drop(page * pageSize) map(_.id) take(pageSize)

db.run(pageQuery.result) flatMap {
case ids: Seq[Int] =>
val query = for {
post <- postTable if post.id inSetBind ids
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)

val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}
}

但这需要两次访问数据库并使用 in运算符,所以它可能不如连接查询。

有什么建议?

最佳答案

你可以这样做:

  def findPagination(from: Int, to: Int): Future[Seq[(Post, Seq[Tag])]] = {
val query:DBIO[Seq[(Album,Seq[Genre])]] = postRepository.findAll(from, to).flatMap{posts=>
DBIO.sequence(
posts.map{ post=>
tagRepository.findByPostId(post.id).map(tags=>(post,tags))
}
)
}
db.run(query)
}

PostRepository
def findAll(from: Int, limit: Int): DBIO[Seq[Post]] = postTable.drop(from).take(limit).result

TagRepository
  def findByPostId(id: Int): DBIO[Seq[Tag]] = {
val query = for {
tag <- tagTable
pstTag <- postTagTable if pstTag.postId === id && tag.id === pstTag.tagId
} yield tag
query.result
}

编辑

我认为如果没有在单个查询中进行子选择,您就无法做到这一点。您当前的解决方案是最好的解决方案。您也可以通过删除不必要的“加入”来优化您的查询
val query = for {
pagePost <- pageQuery
postTag <- postTagTable if pagePost.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (pagePost, tag)

你会得到大约下一个 SQL (Slick 3.0.1):
SELECT x2.`postname`,
x2.`id`,
x3.`tagname`,
x3.`id`
FROM
(SELECT x4.`postname` AS `postname`, x4.`id` AS `id`
FROM `POST` x4 LIMIT 10, 1) x2,
`POST_TAG` x5,
`TAG` x3
WHERE (x2.`id` = x5.`postId`)
AND (x5.`tagId` = x3.`id`)

也许在您的情况下,预编译此查询也更有效
http://slick.typesafe.com/doc/3.0.0/queries.html#compiled-queries

关于sql - 在 Slick 3.0 中结合分页和非查询分组的好方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32016938/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com