【问题标题】:Order By Before Group By in JPA Spring Repository在 JPA Spring 存储库中的 Group By 之前排序
【发布时间】:2014-10-07 08:33:43
【问题描述】:

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

我需要在 group 之前执行 order by 的查询。

我知道在 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

但是我不知道如何通过使用休眠在 jpa 存储库中的查询来执行类似的连接。 我知道这不起作用,因为“in”导致订单丢失

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 存储库中执行此查询?

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

书籍设置为

书 |作者|信息编号

那么 info id 有:

信息|语言|时间戳 |状态|…………

一个示例的目标是: 获取 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 中时间戳最高)

【问题讨论】:

  • 分组依据(2 个字)?
  • 您认为会有更多具有相同信息 ID 的书籍吗?或者同一本书会有更多的信息ID?不同的书本可以有不同的作者,可以吗?
  • 嗨抱歉不清楚每本书都有自己的信息ID。一位作者将拥有多本书。有多个作者,但我会特别关注一位。因此,目标是获取特定作者的每本书的每种语言的已出版的,否则是最新的。将书籍视为更多的修订。

标签: java sql spring hibernate jpa


【解决方案1】:

不,这不好。 SQL 不适用于有序集,SQL (主要)适用于无序集。这意味着,每个查询、查询结果、子查询等都是无序的记录集。

是的,这是因为理论上这些集合正是你可以在高中学习的集合。

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

如果这种内部排序以某种方式起作用,那只是一些 SQL 服务器的随机行为(旧的 MySQL 版本对这种解决方案特别好奇)。

你想要的是

  1. 两个列(publishedlanguage)在记录中分组
  2. ORDERING这两列所需的记录。

所以:

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(休眠查询语言),但我很快就会对此进行一些研究。

扩展#2:

Mysql 没有窗口功能或任何使 SQL 有用的东西。在古代,这是因为他们没有足够的程序员,想要一个快速的系统,而不是一个聪明的系统。目前,这是因为 MySQL 归 Oracle 拥有,他们想要一个免费的并发到他们的 SQL 服务器。无论如何,MySQL 很糟糕,而且从长远来看,特别是如果你对 Java 足够好,我建议你使用一些更好的 DB(我认为使用 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)

【讨论】:

  • 感谢您的回复。我用其他信息更新了我的答案。查看您的帖子它可能会起作用,按已发布的 AND 语言分组,按语言排序这将大大减少数量,在 java 中循环遍历并跟踪是否已使用语言是可行的。
  • 我建议对已发布和语言进行分组的问题在于,分组意味着如果两个未发布,那么即使第二个具有更大的时间戳,也会采用第一个。这是前面提到的分组前需要订购的问题
  • @user1628284 不,这很糟糕。如果按字段分组,则只能从任何其他列中选择 GROUP-ed 字段或聚合函数(例如“MAX()”)。只有 Mysql 不遵循这一点,因为他们不想让基本的 SQL 初学者的生活变得更加艰难,但即使在那里也是一件损坏的事情。我很快就会给你一个可行的解决方案。
  • @user1628284 终于明白你的问题了!这很有趣,不能用简单的 group & order 的东西来完成! (或者只是非常有问题)。您使用哪种 SQL?使用休眠也很困难。在你的位置,我尝试使用一些棘手的 SQL 视图。
  • 感谢您的帮助。它在 mysql 服务器上,但是我使用 JPQL 在使用 hibernate 的 spring 存储库中编写查询。我可能会让它变得非常低效,只检索所有语言,然后一一循环。我花了一天时间,并没有取得太大的成功。
猜你喜欢
  • 2011-11-18
  • 2022-01-10
  • 2015-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-03
相关资源
最近更新 更多