【问题标题】:Find gap in sequence with Java Persistence Query Language使用 Java 持久性查询语言按顺序查找间隙
【发布时间】: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 完成吗? 这背后的原因是能够从一种类型的数据库切换到另一种类型的数据库。

【问题讨论】:

    标签: spring spring-boot jpa spring-data-jpa


    【解决方案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的差距。我想这并不难,因为您可以多次查询。
    猜你喜欢
    • 1970-01-01
    • 2011-06-17
    • 2013-06-30
    • 2011-08-03
    • 2019-11-19
    • 1970-01-01
    • 2015-06-18
    • 1970-01-01
    相关资源
    最近更新 更多