3

有人知道如何在 Scala Query 中归档多对多吗?

我想将博客文章连接到一系列标签。
这是我的数据库设计: 在此处输入图像描述

我的自定义代码已经成功,但是在检查 Scala 查询生成的 SQL 时,我对我的解决方案不满意。
我使用了一种函数式方法,它生成了许多 SQL 查询,从而导致了很多往返。
我可以弄清楚如何将查询数量减少大约一半。

一个手工制作的查询,它可以在一个查询中获取我所有格式良好的数据,

select 
    p.id, p.content, p.posted_date, GROUP_CONCAT(t.name)
from
    post p,
    tag t,
    tag_post tp
where
    tp.post_id = p.id and tp.tag_id = t.id
group by
    p.id

Scala Query 生成的查询提供相同的数据。

SELECT `t1`.`id`,`t1`.`content`,`t1`.`posted_date` FROM `post` `t1`
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=2)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=3)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=4)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=5)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=6)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=7)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=8)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=9)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=10)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=11)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=12)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=13)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=14)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=15)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=16)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=17)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=2)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=18)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=19)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=1)
SELECT `t1`.`id`,`t1`.`name` FROM `tag` `t1` WHERE (`t1`.`id`=3)
SELECT `t1`.`tag_id` FROM `tag_post` `t1` WHERE (`t1`.`post_id`=20)

我担心所有这些往返旅行可能会带来太多开销。

有没有人成功地制作了一个不错的 Scala Query 多对多实现?

4

2 回答 2

3

编辑
您可以像这样模拟 group_concat :

val groupConcat = SimpleFunction[String]("GROUP_CONCAT")

如果您在查询范围内创建此方法,它应该很简单:

yield (alias.a, alias.b, groupConcat(alias.c))

由于我将这些辅助函数存储在抽象数据库包装器中并在特定的 DBMS(如 MySQL)中实现,因此它变得有点复杂,因为 SimpleFunction 类型签名需要这个抽象方法定义:

val groupConcat: ( Seq[Column[_]] => OperatorColumn[String] )

这意味着实现需要传入一个 Seq(alias.c),这有点违反直觉,我们只是传入一个列。无论如何,很高兴它可以工作, GROUP_CONCAT 在 MySQL 中非常方便

原始
上帝知道没有发布您的代码有什么问题,但试试这个:

val q = (for {
  tp <- TagPost
  p  <- Post if tp.post_id is p.id
  t  <- Tag  if tp.tag_id is t.id
  _  <- Query groupBy p.id
} yield (p.id, p.content, p.posted_date, group_concat(t.name)))
println(q.selectStatement)

您将需要创建一个函数来复制 MySQL 的 GROUP_CONCAT。请参阅SimpleFunction 源代码;此对象的一元方法允许您将命名列传递给底层 DBMS 函数。

val group_concat =
  SimpleFunction.unary[NamedColumn[String], String]("GROUP_CONCAT")
于 2012-05-06T09:03:04.510 回答
1

我终于完成了这个方法。
不幸的是,它是特定于供应商的。

def allPosts = database.withSession { implicit db: Session =>
    val group_concat_string_tmp = SimpleFunction[String]("GROUP_CONCAT")
    def group_concat_string(c: Column[String]) = group_concat_string_tmp(Seq(c))
    def group_concat_long(c: Column[Long]) = group_concat_string_tmp(Seq(c))
    val query = for{
       tp <- TagPostTable 
       tag <- TagTable if tp.tag_id is tag.id
       post <- PostTable if tp.post_id is post.id
       _ <- Query groupBy post.id 
     } yield post.id ~ post.content ~ post.postedDate ~ group_concat_long(tag.id) ~ group_concat_string(tag.name)
     println(query.selectStatement)
     def parseToTagList(ids: String, names: String) : List[Tag] = {
       (ids.split(',') map (_.toLong) , names.split(',')).zipped map (Tag(_,_)) toList
     }
     query.list map (queryResult => Post(queryResult._1, queryResult._2, queryResult._3, Option(parseToTagList(queryResult._4, queryResult._5) )))
  }

生成的 SQL 查询是单数的 :) 是的!

SELECT `t1`.`id`,`t1`.`content`,`t1`.`posted_date`,GROUP_CONCAT(`t2`.`id`),GROUP_CONCAT(`t2`.`name`) 
FROM `tag_post` `t3`,`post` `t1`,`tag` `t2` 
WHERE (`t3`.`tag_id`=`t2`.`id`) AND (`t3`.`post_id`=`t1`.`id`) 
GROUP BY `t1`.`id`
于 2012-05-06T13:36:12.037 回答