【问题标题】:How to simplify this UNION query (remove the UNION)?如何简化此 UNION 查询(​​删除 UNION)?
【发布时间】:2021-01-30 21:34:49
【问题描述】:

我有一张玩家桌,我们称之为player

假设它们有 3 列:userId (UUID in a varchar(255))、levelNumber (integer) 和一个与 FetchType.Lazy 一对一关系的列,假设为 facebookProfile

我需要检索“围绕”玩家的排名,因此给定玩家上方的 9 个玩家和给定玩家下方的 9 个玩家,总共有 19 个玩家(我的玩家在中间)。

前段时间我刚想出这个主意:

(select * from player where current_level >= :levelNumber + 1 and (not userid = :userIdToIgnore) order by current_level asc limit 9)
union
(select * from player where  current_level <= :levelNumber - 1 and (not userid = :userIdToIgnore) order by current_level desc limit 9)

你明白了。

有什么方法可以简化它,使其不使用 UNION? 我在问,因为我需要将其转换为 JPQL 查询,所以它不会是 nativeQuery。 这完全是因为nativeQueries 导致了N+1 问题,并且我在延迟加载(facebookProfile 列)和稍后的多项选择方面遇到了麻烦。这就是为什么我需要简化该算法以便能够使用 JPQL。

【问题讨论】:

  • 我想删除联合并使其成为单选、使用连接选择或使用子选择进行选择。由于 JPQL 不支持 UNIONS,任何适用于 JPQL 的东西。

标签: postgresql select optimization lazy-loading jpql


【解决方案1】:

我认为您可以使用窗口函数和条件表达式来做到这一点:

select *
from (
    select p.*, 
        case when current_level >= :levelNumber + 1 then row_number() over(order by current_level)      end rn1, 
        case when current_level <= :levelNumber - 1 then row_number() over(order by current_level desc) end rn_desc
    from player p
    where userid <> :userIdToIgnore and (current_level >= :levelNumber + 1 or current_level <= :levelNumber - 1)
) t
where rn1 between 1 and 9 or rn2 between 1 and 9

【讨论】:

  • 如果能用 JPQL 表达我会很惊讶
  • @a_horse_with_no_name:我对 JPQL 一无所知,所以我相信你。我在 OP 的评论下工作:选择一个,选择连接或选择子选择
  • 据我所知,JPQL 仅限于最基本的 SQL:92 事物(不包括 UNION ;))。它不支持任何现代 SQL 功能。
  • 好的,我想我会把它分成 2 个单独的查询:D 感谢大家抽出宝贵的时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 2013-10-04
  • 1970-01-01
  • 2020-05-08
相关资源
最近更新 更多