SQL Server 数据库中带有 Group by 子句的 JPQL 不起作用

Posted

技术标签:

【中文标题】SQL Server 数据库中带有 Group by 子句的 JPQL 不起作用【英文标题】:JPQL with Group by clause in SQL Server database not working 【发布时间】:2021-12-16 12:34:36 【问题描述】:

我是 SQL Server 数据库的新手。下面的 JPQL 查询没有被执行,也没有抛出任何错误。只是我的应用程序挂在这个查询上。此代码适用于 mysql 数据库,但不适用于 SQL Server(2019) 数据库。

@Query(value = "SELECT R.riskType, count(distinct V.bname) FROM RiskViolation V JOIN V.job J JOIN V.risk R WHERE J.id = ?1 GROUP BY R.riskType ")
public List<Object[]> sodUserByRiskType(Long jobId);

但是当我直接在 SQL Server 数据库中运行以下转换后的 sql 查询时,它工作正常。

select count(distinct riskviolat0_.bname) as col_1_0_, risklog2_.risk_type as col_0_0_ from risk_violation riskviolat0_ inner join analysis_job analysisjo1_ on riskviolat0_.job_id=analysisjo1_.id inner join risk_log risklog2_ on riskviolat0_.risk_id=risklog2_.id where analysisjo1_.id=? group by risklog2_.risk_type;

以下是 JPQL 查询中使用的 Java 实体类:

RiskViolation.java

@Entity
@Table(name = "risk_violation")
public class RiskViolation 

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "job_id")
private AnalysisJob job;

private String bname;

private String riskName;

private String violations;

@Column(name = "violated", columnDefinition = "BIT", length = 1)
private boolean violated;

@Column(name = "simulation", columnDefinition = "BIT", length = 1)
private boolean simulation;

@Column(name = "mitigation_name")
private String mitigationName;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "risk_id")
private RiskLog risk;

@JsonIgnore
@OneToMany(mappedBy = "riskViolation", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<RuleViolation> ruleViolations;

AnalysisJob.java

@Entity
@Table(name = "analysis_job")
public class AnalysisJob 

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "profile_name")
private String profileName;

@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "profile_id")
@OnDelete(action = OnDeleteAction.CASCADE)
private AnalysisProfileLog profileLog;

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

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

@Column(name = "started_on")
private Date startedOn;

@Column(name = "completed_on")
private Date completedOn;

@Column(name = "completion_message")
private String completionMessage;

@Column(name = "percent_completed")
private float percentCompleted;

@Column(name = "run_by")
private String runBy;

@Column(name = "removed", columnDefinition = "BIT", length = 1)
private boolean removed;

@OneToMany(mappedBy = "job", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private List<JobResultData> resultData;

@Column(name = "pos_analysis", columnDefinition = "BIT", length = 1)
private boolean posAnalysis;

@Column(name = "submitted", columnDefinition = "BIT", length = 1)
private boolean submitted;

@Column(name = "position_id")
private String positionId;

RiskLog.java

@Entity
@Table(name = "risk_log")
public class RiskLog 

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Long jobId;

private String name;

private String riskDescription;

private String riskCondition;

private String businessProcess;

@Column(name = "business_sub_process")
private String subProc;

private String riskType;

@JsonIgnore
@OneToMany(mappedBy = "riskLog", cascade = CascadeType.ALL)
protected List<RuleLog> rules;

是否需要对查询和实体类进行任何更改才能使其正常工作?

这里是Query Plan URL

Estimated Execution Plan

Actual Execution Plan

Query Plan with Actual Rows

【问题讨论】:

请通过brentozar.com/pastetheplan分享查询计划。要获得正在运行的查询计划,请在 Jpql 执行查询 select qp.query_plan from sys.dm_exec_requests r cross apply sys.dm_exec_query_plan(r.plan_handle) qp where r.session_id &lt;&gt; @@SPID 时在 SSMS 中运行它 感谢@Charlieface 的回复。我已经用底部的查询计划 url 更新了我的问题。 尝试索引risk_violation (job_id, bname),您无能为力。您可以从 SSMS 上传“实际”执行计划吗?最终结果集有多少行,从预估的计划中看不到? 按照您的建议添加了索引,但仍然相同。我不确定我是否正确运行查询计划。这次我在工具栏上选择了“包括实际执行计划”和“包括实时查询统计”选项并执行。请查看带有新查询计划的更新问题。 现在,我知道了如何获得实际的查询计划。给我几分钟,我会补充的。 【参考方案1】:

它在避免 Java 类(我的业务逻辑所在的位置)和 JPA 存储库(用于执行 JPQL 查询)之间的外观类之后起作用。从 Java 类直接调用 JPA 存储库方法。不知道为什么它不适用于带有 SQL Server 的外观类,但同样适用于 MySQL 数据库。

【讨论】:

以上是关于SQL Server 数据库中带有 Group by 子句的 JPQL 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

列子句中带有子查询的 MS SQL Server 数据透视表

SQL Server 中带有 while 循环的用户定义函数

SQL Server 中带条件的 Where 子句

在 SQL Server 中跨两个表协调列

关于sqlserver 数据库的group分组问题,在线等待回答

GROUP_CONCAT 中带有“,”分隔符的 DISTINCT 值