【问题标题】:How to write Inner Query Programatically to fetch latest record based on condition如何以编程方式编写内部查询以根据条件获取最新记录
【发布时间】:2020-06-01 13:16:46
【问题描述】:

我的用例是根据 SQL 表中的一些过滤条件查找最新记录(按日期)。我已经构建了 SQL 查询并通过 SQL IDE 运行它,它工作正常。我正在使用 MS Sql Serve 作为我的数据库。

但是当我尝试使用 Spring-Data JPA/Criteria 以编程方式转换此查询时,我不知道如何实现。

这是我根据 src_cc、src_nbr 和 isvariableWeight 查找最新记录的查询:-

    SELECT *
    FROM
    dcfin_test Tab1
    INNER JOIN (
        SELECT
            ibd_doc_nbr,
            ibd_doc_line_nbr,
            MAX(create_ts) AS max_Ts
        FROM
            dcfin_test
        WHERE
            src_cc = 'US'
            AND src_nbr = 6938
            AND isvariableWeight = 'Y'
        GROUP BY
            ibd_doc_nbr,
            ibd_doc_line_nbr) Tab2 ON Tab1.ibd_doc_nbr = Tab2.ibd_doc_nbr
    AND Tab1.ibd_doc_line_nbr = Tab2.ibd_doc_line_nbr
    AND Tab1.create_ts = Tab2.max_Ts;

这里 src_cc、src_nbr 和 isVaribaleWe​​ight 将在运行时以编程方式传递。上面显示的目的是为了举例。

这是我的实体模型的样子(其他不需要的列已被删除):-

import java.math.BigDecimal;
import java.time.Instant;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;


@Entity
@Table(name = "dcfin_test")
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WeightedAlertEntity {

@Id
@Column(name = "weightedAlertId")
private String weightedAlertId;

@Column(name = "src_cc")
private String sourceCC;

@Column(name = "src_nbr")
private int sourceNbr;

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

@Column(name = "ibd_doc_nbr")
private String inboundDocNbr;

@Column(name = "ibd_doc_line_nbr")
private String inboundDocNbrLineNbr;

@Column(name = "item_nbr")
private String itemNbr;


@Column(name = "wac_percent_change")
private BigDecimal percentWacChange;

@Column(name = "waw_percent_change")
private BigDecimal percentWawChange;

@Column(name = "created_by")
private String createdBy;

@Column(name = "create_ts")
private Instant createTs;

}

我尝试在 Spring Data JPA 中使用本机查询,它看起来如下:-

@Repository
public interface WeightedAlertEntityDao
extends JpaRepository<WeightedAlertEntity, String> {

@Query(value = "SELECT * FROM dcfin_weighted_alert_data Tab1 "
        + "INNER JOIN ("
        + "SELECT ibd_doc_nbr,ibd_doc_line_nbr,MAX(create_ts) AS max_Ts FROM dcfin_weighted_alert_data"
        + " WHERE src_cc = ?1 AND src_nbr = ?2 AND weight_format_type = ?3 "
        + "GROUP BY ibd_doc_nbr, ibd_doc_line_nbr) Tab2 "
        + "ON Tab1.ibd_doc_nbr = Tab2.ibd_doc_nbr "
        + "AND Tab1.ibd_doc_line_nbr = Tab2.ibd_doc_line_nbr "
        + "AND Tab1.create_ts = Tab2.max_Ts", nativeQuery = true)
public List<WeightedAlertEntity> getAlertEntityBasedOnFilterCondition(
    String sourceCC, Integer srcNbr, String weightFormatType);

}

当我从我的服务层调用上述方法时:-

List<WeightedAlertEntity> alertEntityBasedOnFilterCondition = weightedAlertDao.getAlertEntityBasedOnFilterCondition(
        header.getFacilityCountryCode(),Integer.parseInt(header.getFacilityNum()),
        weightFormatType);

更新我的问题:-

我已经彻底检查过,发现有一个错误导致列名无效,因为我使用 Tab2.create_ts 代替了 Tab2.max_Ts。现在我可以得到结果了。

作为此查询的一部分,我也需要分页支持,即如果用户输入 pageNum = 1 和 pagesize = 10,如果记录更多,我应该能够返回 10 个结果。 当用户输入 pageNum = 2, pageSize = 10 时,我应该返回接下来的 10 条记录。

有人可以调查一下并指导我如何使用 Spring Data Jpa / Criteria 实现这一目标吗?

【问题讨论】:

  • 如果您只想要modified_tsMAX 值,为什么不在外部查询中使用窗口化的MAX?这里不需要子查询。
  • 我正在寻找完整的行数据(它将是记录列表),而不仅仅是 modfied_ts。 Modified_ts 是用于查找最新记录的列。
  • 有一个复杂的查询,但您还没有展示如何在 JPA 中映射任何内容。你的模型是什么样的,你尝试了什么,你希望在你的应用程序中使用什么结果?分页是在您计算完其他所有内容之后进行的 - 否则,只需使用本机 SQL 查询并获取原始数据。
  • @Chris 我已经根据我迄今为止的尝试编辑了这个问题。

标签: sql-server jpa spring-data-jpa criteria


【解决方案1】:

您正在寻找的是“每组前 N 个项目”的解决方案。在你最喜欢的搜索引擎中使用这个短语,就会出现几种解决问题的方法。我会选择的是

  • 窗口函数
  • CROSS APPLY 加入子查询。

【讨论】:

  • 如您所见,我已经编写了 SQL 来根据条件查找 TOP n 项。我基本上希望使用 Spring Data JPA/本机 Quert/Criteria 以编程方式转换。
【解决方案2】:

我已经彻底检查过,发现有一个错误导致列名无效 (create_ts),因为我使用 Tab2.create_ts 代替了内部查询中的 Tab2.max_Ts。现在我可以得到结果了。

现在,当我尝试使用 Pageable 进行分页时,如下所示:-

            Page<WeightedAlertEntity> alertEntityBasedOnFilterCondition = weightedAlertDao.getAlertEntityBasedOnFilterCondition(
                header.getFacilityCountryCode(),
                Integer.parseInt(header.getFacilityNum()),
                weightFormatType, PageRequest.of(0, 10));

这是我的存储库类的样子:-

@Repository
public interface WeightedAlertEntityDao
extends JpaRepository<WeightedAlertEntity, String> {

@Query(value = "SELECT * FROM dcfin_weighted_alert_data as Tab1 "
        + "INNER JOIN ("
        + "SELECT Tab3.ibd_doc_nbr,Tab3.ibd_doc_line_nbr,MAX(Tab3.create_ts) AS max_Ts FROM dcfin_weighted_alert_data as Tab3"
        + " WHERE Tab3.src_cc = ?1 AND Tab3.src_nbr = ?2 AND Tab3.weight_format_type = ?3 "
        + "GROUP BY Tab3.ibd_doc_nbr, Tab3.ibd_doc_line_nbr) as Tab2 "
        + "ON Tab1.ibd_doc_nbr = Tab2.ibd_doc_nbr "
        + "AND Tab1.ibd_doc_line_nbr = Tab2.ibd_doc_line_nbr "
        + "AND Tab1.create_ts = Tab2.max_Ts", nativeQuery = true)
public Page<WeightedAlertEntity> getAlertEntityBasedOnFilterCondition(
    String sourceCC, Integer srcNbr, String weightFormatType, Pageable pageable);

}

我收到此错误:- 为“inner_query”多次指定了“ibd_doc_nbr”列。

当我尝试使用 SQL IDE 时,查询相同,它工作正常。有人可以帮助我在哪里做错了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-07
    • 2019-07-20
    • 1970-01-01
    • 2016-08-14
    相关资源
    最近更新 更多