java 转换QueryDsl中包含WITH子句和联合的SQL查询

2j4z5cfb  于 2023-02-28  发布在  Java
关注(0)|答案(1)|浏览(204)

我正在使用Oracle数据库,并有学生表:
学生桌:

| COLUMN      | TYPE          |
| ----------- | ------------- |
|  ID         | VARCHAR2(200) |
|  NAME       | VARCHAR2(200) |
|  AGE        | NUMBER(5)     |
|  MAIN_CITY  | VARCHAR2(200) |
|  GENDER     | VARCHAR2(50)  |
|  SCORE      | FLOAT(5)      |

'
我正在尝试将此SQL查询转换为query-dsl代码:

SELECT /*+ parallel(2)*/ *
FROM (WITH filtered_values(age, gender, main_city) AS
(
SELECT /*+ MATERIALIZE */ age, gender, main_city 
FROM Students
-- GET CONDITIONS FROM USER AND FILTER THE QUERY USING WHERE
)
SELECT * 
FROM (
SELECT age AS value, COUNT(*) AS row_count, 'age' AS column_name
FROM filtered_values
GROUP BY age
ORDER BY row_count)
WHERE rownum <= 5
UNION ALL (
SELECT * 
FROM (
SELECT gender AS value, COUNT(*) AS row_count, 'gender' AS column_name
FROM filtered_values
GROUP BY gender
ORDER BY row_count)
WHERE rownum <= 5)
UNION ALL (
SELECT * 
FROM (
SELECT main_city AS value, COUNT(*) AS row_count, 'main_city' AS column_name
FROM filtered_values
GROUP BY main_city
ORDER BY row_count)
WHERE rownum <= 5)
)

客户端提供的筛选器非常灵活,可以更改WITH查询,例如:
评分大于20时:
WITH filtered_values(年龄,性别,主要城市)AS(SELECT/*+ MATERIALIZE /年龄,性别,主要城市FROM分数〉20的学生)
其中城市为LA或NYC,评分在50 - 60之间:
WITH filtered_values(年龄,性别,主要城市)AS(SELECT/
+ MATERIALIZE */年龄,性别,主要城市FROM学生WHERE主要城市IN('LA ',' NYC')AND分数〉= 50 AND分数〈= 60)
我使用的是QueryDsl版本5.0.0。
我创建了Java类:
学生:

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(schema = "PROD", name = "Students")
public class Student implements Serializable {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME")
private String name;
@Column(name = "AGE")
private int age;
@Column(name = "MAIN_CITY")
private String mainCity;
@Column(name = "SCORE")
private float score; 
}

聚合值:

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(schema = "PROD", name = "NOT_REAL_TABLE")
public class AggregationValues {
private int age;
private String gender;
private String mainCity;
}

聚合结果行:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class AggregationResultRow {
private String value;
private long rowCount;
private String columnName;
}

我的代码是:
注意,this.getConditions(aggregationsRequest)从客户端返回带有所有过滤器的BooleanBuilder。

private final QStudent table = QStudent.student;
private final QAggregationValues aggregationValues = QAggregationValues.aggregationValues;

public List<AggregationResultRow> getAggergations(AggregationRequest aggregationRequest) {
SubQueryExpression<AggregationValues> filteredValues = new BlazeJPAQuery<AggregationValues>(entityManager, criteriaBuilderFactory)
.select(Projections.constructor(AggregationValues.class, 
this.table.age,
this.table.gender,
this.table.mainCity))
.from(this.table)
.where(this.getConditions(aggregationRequest));

BlazeJPAQuery<AggregationResultRow> ageSelect = new BlazeJPAQuery<AggregationResultRow>(entityManager, criteriaBuilderFactory)
.with(this.aggregationValues, filteredValues)
.select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.age.as("value"),
this.aggregationValues.count().as("row_count"),
Expressions.asString("age").as("column_name")))
.from(this.aggregationValues)
.groupBy(this.aggregationValues.age);

BlazeJPAQuery<AggregationResultRow> genderSelect = new BlazeJPAQuery<AggregationResultRow>(entityManager, criteriaBuilderFactory)
.with(this.aggregationValues, filteredValues)
.select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.gender.as("value"),
this.aggregationValues.count().as("row_count"),
Expressions.asString("gender").as("column_name")))
.from(this.aggregationValues)
.groupBy(this.aggregationValues.gender);

BlazeJPAQuery<AggregationResultRow> mainCitySelect = new BlazeJPAQuery<AggregationResultRow>(entityManager, criteriaBuilderFactory)
.with(this.aggregationValues, filteredValues)
.select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.mainCity.as("value"),
this.aggregationValues.count().as("row_count"),
Expressions.asString("main_city").as("column_name")))
.from(this.aggregationValues)
.groupBy(this.aggregationValues.mainCity);

return ageSelect.unionAll(genderSelect, mainCitySelect).fetch();
}

但我得到了异常-java.lang.IllegalArgumentException: Don't mix union and from
我已经尝试了更多的代码想法,但没有工作,这一个看起来最接近我的查询。
有什么想法吗?
非常感谢,我会非常感激的!

wvt8vs2t

wvt8vs2t1#

所以我找到了一个折中的解决方案!我所做的是在类中添加autowired参数:

@Autowired
private JdbcTemplate jdbcTemplate;

这个函数是:

public List<AggregationResultRow> getAggregations(AggregationRequest aggregationRequest) throw Exception {
Connection connection = this.jdbcTemplate.getDataSource().getConnection();
OracleQuery<AggregationResultRow> query = new OracleQuery<AggregationResultRow>(connection)
.with(this.aggregationValues, new OracleQuery<AggregationValues>(connection)
.select(Projections.constructor(AggregationValues.class, this.table.age.as(this.aggregationValues.age), this.table.gender.as(this.aggregationValues.gender),
this.table.mainCity.as(this.aggregationValues.mainCity)))
.from(this.table)
where(this.getConditions(aggregationRequest)));

query.unionAll(new OracleQuery<AggregationResultRow>(connection)
.select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.age.as(“value”),
this.aggregationValues.age.count().as(“row_count”),
Expressions.asString(“age”).as(“column_name”)))
.from(this.aggregationValues)
.groupBy(this.aggregationValues.age),
new OracleQuery<AggregationResultRow>(connection)
.select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.gender.as(“value”),
this.aggregationValues.gender.count().as(“row_count”),
Expressions.asString(“gender”).as(“column_name”)))
.from(this.aggregationValues)
.groupBy(this.aggregationValues.gender),
new OracleQuery<AggregationResultRow>(connection)
.select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.mainCity.as(“value”),
this.aggregationValues.mainCity.count().as(“row_count”),
Expressions.asString(“mainCity”).as(“column_name”)))
.from(this.aggregationValues)
.groupBy(this.aggregationValues.mainCity));

return query.fetch();
}

现在我只需要在WITH子句中的select语句中添加物化,并与所有函数并行。有什么想法吗?

相关问题