【问题标题】:What should LIMIT have for attributes in Spring JPA? SQLSpring JPA 中的属性 LIMIT 应该有什么? SQL
【发布时间】:2021-01-08 00:30:25
【问题描述】:

我正在尝试限制 nativeQuery = true,但 Spring JPA 找不到此查询。

我的错误是:

Caused by: java.lang.IllegalStateException: Using named parameters for method public abstract void se.danielmartensson.repositories.DataRepository.deleteByJobNameOrderByDateTimeLimit(java.lang.String,long,long) but parameter 'Optional[jobName]' not found in annotated query 'DELETE FROM Data data ORDER BY data.dateTime WHERE data.jobName =: jobName LIMIT firstIndex = :firstIndex, selectedSamples = :selectedSamples'!

所以我猜 LIMIT 应该有不同的属性,而不是 firstIndex 和 selectedSamples ?那会是什么呢?

我在 Spring Boot 中的 Repository 的查询在哪里

@Query(value = "SELECT * FROM Data data ORDER BY data.dateTime WHERE data.jobName = :jobName LIMIT firstIndex = :firstIndex, selectedSamples = :selectedSamples", nativeQuery = true)
List<Data> findByJobNameOrderByDateTimeLimit(@Param("jobName") String jobName, @Param("firstIndex") long firstIndex, @Param("selectedSamples") long selectedSamples);

@Modifying
@Query(value = "DELETE FROM Data data ORDER BY data.dateTime WHERE data.jobName =: jobName LIMIT firstIndex = :firstIndex, selectedSamples = :selectedSamples", nativeQuery = true)
void deleteByJobNameOrderByDateTimeLimit(@Param("jobName") String jobName, @Param("firstIndex") long firstIndex, @Param("selectedSamples") long selectedSamples);

【问题讨论】:

  • 我想你在这里打错了=: jobName LIMIT
  • @T.Peter 谢谢。现在我得到了Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE data.jobName = 'Test3' LIMIT firstIndex = 0, selectedSamples = 104' at line 1,我尝试在Test3 和LIMIT 之间使用AND,但没有成功。
  • 恳请您重新编辑评论中包含问题的帖子,以便新人发现实际问题。
  • 另外limit是一个用于设置SQL返回的元组数量上限的子句。我不认为limit 是你想在这里做的。

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


【解决方案1】:

我创建了一个使用H2 的示例项目。您必须更改您使用的数据库中的limit 和offset 部分。对于删除操作,定义了delete from table where id in (select id from table where .. order by .. limit .. offset ..)。

注意:Lombok 用于getter、setter 和toString。这不是必需的。

DataRepository.java

public interface DataRepository extends JpaRepository<Data, Integer> {
    @Query(value = "SELECT * FROM Data data WHERE data.jobName = :jobName ORDER BY data.dateTime limit :selectedSamples offset :firstIndex"
            , nativeQuery = true)
    List<Data>findByJobNameOrderByDateTimeLimit(@Param("jobName") String jobName, @Param("firstIndex") Integer firstIndex, @Param("selectedSamples") Integer selectedSamples);

    @Transactional
    @Modifying
    @Query(value = "DELETE FROM Data data WHERE data.id in (select id from Data d where d.jobName = :jobName order by d.dateTime limit :selectedSamples offset :firstIndex)"
            , nativeQuery = true)
    void deleteByJobNameOrderByDateTime(@Param("jobName") String jobName, @Param("firstIndex") Integer firstIndex, @Param("selectedSamples") Integer selectedSamples);
}

Data.java

@lombok.Data
@Entity
@Table
public class Data {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column(name = "jobName")
    private String jobName;

    @Column(name = "dateTime")
    private LocalDateTime dateTime;

    public Data() {
    }

    public Data(String jobName, LocalDateTime dateTime) {
        this.jobName = jobName;
        this.dateTime = dateTime;
    }
}

测试

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.time.LocalDateTime;
import java.util.List;

@SpringBootTest
class DemoApplicationTests {
    @Autowired
    private DataRepository dataRepository;
    
    @Test
    void test1() {
        // insert dummy records
        dataRepository.save(new Data("job1", LocalDateTime.now().minusMinutes(1)));
        dataRepository.save(new Data("job1", LocalDateTime.now().minusMinutes(2)));
        dataRepository.save(new Data("job1", LocalDateTime.now().minusMinutes(3)));
        dataRepository.save(new Data("job1", LocalDateTime.now().minusMinutes(4)));

        // get records
        List<Data> dataList = dataRepository.findByJobNameOrderByDateTimeLimit("job1", 0, 4);
        for (Data data : dataList) {
            System.out.println(data);
        }

        // delete
        dataRepository.deleteByJobNameOrderByDateTime("job1", 1, 2);

        // get records
        dataList = dataRepository.findByJobNameOrderByDateTimeLimit("job1", 0, 4);
        for (Data data : dataList) {
            System.out.println(data);
        }
    }
}

输出

Hibernate: SELECT * FROM Data data WHERE data.jobName = ? ORDER BY data.dateTime limit ? offset ?

Data(id=4, jobName=job1, dateTime=2021-01-08T05:25:31.830)
Data(id=3, jobName=job1, dateTime=2021-01-08T05:26:31.829)
Data(id=2, jobName=job1, dateTime=2021-01-08T05:27:31.827)
Data(id=1, jobName=job1, dateTime=2021-01-08T05:28:31.756)

Hibernate: DELETE FROM Data data WHERE data.id in (select id from Data d where d.jobName = ? order by d.dateTime limit ? offset ?)

Hibernate: SELECT * FROM Data data WHERE data.jobName = ? ORDER BY data.dateTime limit ? offset ?

Data(id=4, jobName=job1, dateTime=2021-01-08T05:25:31.830)
Data(id=1, jobName=job1, dateTime=2021-01-08T05:28:31.756)

Mysql

对于mysql,使用以下脚本删除操作成功。

参考:MySQL DELETE FROM with subquery as condition - Answer

    @Transactional
    @Modifying
    @Query(value = "DELETE FROM Data WHERE id in (select id from (select id from Data where jobName = :jobName order by dateTime limit :selectedSamples offset :firstIndex) x)"
            , nativeQuery = true)
    void deleteByJobNameOrderByDateTime(@Param("jobName") String jobName, @Param("firstIndex") Integer firstIndex, @Param("selectedSamples") Integer selectedSamples);

【讨论】:

  • 非常好!这是一个很好的答案。不幸的是,它不适用于我的 MySQL 数据库。我不知道我为什么要使用 MySQL。它只是工作。 MySQL 没有关键字ÌN。
  • This version of MySQL doesn't yet support 'LIMIT &amp; IN/ALL/ANY/SOME subquery'
  • 嗨@DanielMårtensson 我从MySQL DELETE FROM with subquery as condition - Answer 找到了答案。它现在正在为 mysql 工作
  • 嗨!这对我有用DELETE FROM data WHERE id IN (SELECT * FROM (SELECT id FROM data WHERE job_name = :jobName ORDER BY date_time ASC LIMIT :selectedLimit OFFSET :selectedOffset) as t) MySQL。
  • 是的。它与您显示的代码相似。非常感谢。
【解决方案2】:

如果您只想获取jobName 和firstIndex 和selectedSamples 匹配参数的行。您应该使用正确的 SQL 语法并将它们放入 where。

SELECT * FROM Data data
WHERE data.jobName = :jobName AND firstIndex = :firstIndex AND selectedSamples = :selectedSamples
ORDER BY data.dateTime

正确的语法是这样的:

select *
from [table]
where 'condiction'
order by [column]
limit [int]

LIMIT 但是用于设置 SQL 返回的最大元组,例如如果查询返回 10K 行但您只想查看前 5 行,则可以使用 limit 5 告诉 SQL 仅返回前 5 个 fetch .

同样在不同的 DBMS 中,可能需要使用不同的语法或方法来实现相同的目标,例如在 ORACLE 中我们没有limit 子句,而是使用FETCH 或简单地使用ROWNUM。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 2015-10-31
    • 2012-07-11
    • 2010-10-21
    • 1970-01-01
    • 2015-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多