使用 Java 持久性查询语言按顺序查找间隙

Posted

技术标签:

【中文标题】使用 Java 持久性查询语言按顺序查找间隙【英文标题】:Find gap in sequence with Java Persistence Query Language 【发布时间】:2021-04-24 17:49:37 【问题描述】:

在我的表中,我有一列就像一个序列,只是它不是自动递增的,递增是在代码中完成的。

表格的粗略表示如下:

id fruit sequence
1 apple 1
2 apple 2
3 apple 3
4 apple 10
5 orange 1
6 orange 2

如您所见,我的序列列中有间隙,我想找到那个间隙,它从哪里开始,从哪里结束。例如,查询以fruit = apple 查找间隙的开头,然后查找间隙的结尾,如下所示:“4-9”

现在我在 JPA 中使用带有本机查询的 this 解决方案: 效果很好,但只能用于 mysql,这可以用 entitymanager 和 JPQL 完成吗? 这背后的原因是能够从一种类型的数据库切换到另一种类型的数据库。

【问题讨论】:

【参考方案1】:

简短的回答是否定的。 JPA 和 JPQL 不适用于像您这样的目的。您遵循的解决方案不是关于 JPA,而是关于 MySQL 问题,并且已相应标记。为什么不将此计算移至服务层?在这种情况下,您将自动摆脱 DBMS 依赖问题。 例如:

public interface FruitRepository extends CrudRepository<Fruit, Long> 
  
  @Query("select f.sequence from Fruit f where f.fruit = :name order by f.sequence"
  List<Long> getSequencesByFruitName(@Param("name") String fruitName);

我在这里添加排序只是为了确保元素将按升序返回。如果这对您来说是无法到达的情况,那么只需将其从查询中删除即可。

好的,那么在Service 层我们将实现计算:

@Service
public class FruitServiceImpl implements FruitService 

  private FruitRepository fruitRepository;

  public FruitServiceImpl(FruitRepository fruitRepository) 
    this.fruitRepository = fruitRepository;
  

  public void logic() 
    ********************
    List<Long> list = fruitRepository.getSequencesByFruitName("apple");
    List<Pair<Long, Long>> gaps = new ArrayList<>();
    for (int i = 0; i < list.size() - 1; i++) 
      if (list.get(i + 1) > list.get(i) + 1) 
        gaps.add(Pair.of(list.get(i) + 1, list.get(i + 1) - 1));
      
    
    ********************    
  
 

【讨论】:

这是一种方法,但这里的问题是性能。在内存中拥有 20000 个项目比执行 sql 查询要慢得多。但我想情况总是如此......不过谢谢!【参考方案2】:

您可以使用以下查询找到序列中的“最低”间隙:

SELECT MIN(s1.sequence) + 1
FROM FruitSequence s1
WHERE NOT EXISTS(
    SELECT id FROM FruitSequence s2
    WHERE s1.fruit = s2.fruit
    AND s1.sequence + 1 = s2.sequence)

您可以重复使用此查询来获取后续的免费 ID。如果使用 Hibernate,您甚至可以使用不相关的连接来代替 EXISTS 运算符。

【讨论】:

这不会得到范围,只有第一个和最低的间隙,对吧? 对,虽然得到了范围的低端,但是很容易写一个(非常相似的)查询来找到高端 我猜,但是如果序列中有多个间隙,它会变得有点棘手...... 怎么样?您正在寻找比没有前任的低端更大的最低序列号(与上述查询中的后继者相反)。间隙的数量无关紧要。 假设您首先找到序列 1 到 3,这可以通过 MIN 和 MAX 完成。但是你也有6-10的差距。我想这并不难,因为您可以多次查询。

以上是关于使用 Java 持久性查询语言按顺序查找间隙的主要内容,如果未能解决你的问题,请参考以下文章

SQL 查询:在主键中查找间隙

1.完整语段的增删改 2.单表查询 3.多表查询

JavaEE Tutorials (10) - Java持久化查询语言

MySQL按顺序查找每组最近/最大的记录

无论如何,为了提高 SQL 查询的性能,以按标签匹配计数查找具有顺序的行

HQL 或 Java 持久性查询语言中的 IN 子句