在JPA Spring Repository中按组排序

时间:2014-10-07 08:33:43

标签: java sql spring hibernate jpa

所以我的目标是获得一本特定的书(带有给定的id),以获得每种语言的已发布版本。如果没有发布的版本,那么我需要通过时间戳检索最新版本。

我需要进行一个查询,按顺序执行订单。

我知道在sql中你可以(大致)

Select * From 
( Select b from Book as b where b.author = ?1 ORDER BY (case when b.info.status=published then 1 else 2) asc, b.timestamp desc)
GroupBy book.language

但是我不知道如何使用hibernate在jpa存储库中进行类似的连接查询。 我知道这不起作用,因为订单因“'

”而丢失
Select a From book a where a.id in  
( Select b from Book as b where b.author=?1 ORDER BY (case when b.info.status=published then 1 else 2) asc, b.timestamp desc)
GroupBy a.language

当它通过并检入时,这意味着订单未被保留。无论如何在jpa存储库中执行此查询?

我不想为每个人做一个'并获得发布/最新,因为这将是非常低效的

书籍设置为

书|作者|信息ID

然后信息ID有:

INFOID |语言|时间戳|状态| .........

示例目标是: 得到j.k.每种语言发布/最新的滚动

书籍的示例设置将是

book | author | info id
1    |Rowling |1 
2    |Rowling |2
3    |Rowling |3
4    |Rowling |4
5    |Tolkein |5

信息:

id|lang|ts | status
1 |en  |1  | published
2 |de  |5  | unpublished
3 |de  |3  | unpublished
4 |en  |9  | unpublished
5 |en  |4  | published

请求它返回书籍 1(已发布和英文),以及2(如de,de de的最高时间戳)

1 个答案:

答案 0 :(得分:1)

不,不行。 SQL不能使用有序集,SQL正在(主要)使用无序集。这意味着,每个查询,查询结果,子查询等都是无序的记录集。

是的,这是因为这些套装在理论上完全是你在高中可以学到的套装。

如果您执行GROUP BYJOIN或任何类似操作,则之前的ORDER BY将失效。为什么?因为每个这样的关键字都使用无序集合。这也是原因,为什么只有最后一个SQL查询才能有ORDER BY

如果以某种方式内部排序有效,它只是某些SQL服务器的随机行为(旧的MySQL版本在此类解决方案中特别好奇)。

你想要的是

  1. 通过两个列(publishedlanguage
  2. 对记录进行分组
  3. 订购这两列所需的记录。
  4. 所以:

    SELECT b FROM Book b WHERE author=?1 AND info.status=published ORDER BY published, language

    ......等等。如果我能破译你想要的东西,甚至可能不需要group by。如果你扩展你的问题,你的目标是什么,我会用查询扩展我的答案。

    扩展名#1:

    它不能用基本的SQL完成,它需要窗口函数。执行所需操作的SQL查询:

    SELECT *, ROW_NUMBER() OVER (ts PARTITION BY author, lang ORDER BY ts) AS tsn FROM Book b LEFT JOIN info i ON b.info_id=i.id WHERE tsn=1

    无论如何,你应该寻找ROW_NUMBER() SQL函数,可能你不会需要GROUP BY

    我不知道如何将它移植到hql(hibernate查询语言),但我会尽快对此进行一些研究。

    扩展#2:

    Mysql没有窗口函数或任何使SQL有用的东西。在古代,这是因为他们没有足够的程序员,想要一个快速的系统,而不是一个聪明的系统。目前,这是因为MySQL归Oracle所有,他们想要一个免费的并发SQL服务器。无论如何,MySQL是坏的,而且长期来说,特别是如果你对Java有足够的好处,我建议你使用一些更好的数据库(对于PostgreSQL你真的很满意,我认为)。

    在此之前,这是一个SQL解决方案。这有点复杂。首先,我们得到每个作者,书籍和语言的最大时间戳:

    SELECT book.author, book.id as book_id, info.lang, MAX(info.ts) AS ts FROM book LEFT JOIN info ON book.info_id=info.id GROUP BY book.author, book.id, info.lang

    我们将此查询称为$queryMaxts。试试这个查询,它应该可以工作。

    之后,我们可以将其加入到我们希望的表格中:

    SELECT * FROM ($queryMaxts) maxts LEFT JOIN book ON maxts.author=book.author LEFT JOIN info ON maxts.lang=info.lang AND maxts.ts=info.ts AND book.info_id=info.id

    ...虽然它是一个纯粹的MySQL解决方案,但没有任何东西可以让JPA去做。我建议以某种方式将其嵌入到JPA图层中。

    另一件重要的事情:

    您几乎可以确定时间戳是唯一的。您可以通过创建唯一索引来保证使数据库更快的原因:CREATE UNIQUE INDEX uniqts ON info(lang, ts)