所以我的目标是获得一本特定的书(带有给定的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的最高时间戳)
答案 0 :(得分:1)
不,不行。 SQL不能使用有序集,SQL正在(主要)使用无序集。这意味着,每个查询,查询结果,子查询等都是无序的记录集。
是的,这是因为这些套装在理论上完全是你在高中可以学到的套装。
如果您执行GROUP BY
,JOIN
或任何类似操作,则之前的ORDER BY
将失效。为什么?因为每个这样的关键字都使用无序集合。这也是原因,为什么只有最后一个SQL查询才能有ORDER BY
。
如果以某种方式内部排序有效,它只是某些SQL服务器的随机行为(旧的MySQL版本在此类解决方案中特别好奇)。
你想要的是
published
和language
)所以:
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)
。