将包含WITH子句和UNION的SQL查询转换为QueryDsl。

huangapple go评论109阅读模式
英文:

Convert SQL query that contains WITH clause and union in QueryDsl

问题

以下是翻译好的代码部分:

  1. private final QStudent table = QStudent.student;
  2. private final QAggregationValues aggregationValues = QAggregationValues.aggregationValues;
  3. public List<AggregationResultRow> getAggregations(AggregationRequest aggregationRequest) {
  4. SubQueryExpression<AggregationValues> filteredValues = new BlazeJPAQuery<AggregationValues>(entityManager, criteriaBuilderFactory)
  5. .select(Projections.constructor(AggregationValues.class,
  6. this.table.age,
  7. this.table.gender,
  8. this.table.mainCity))
  9. .from(this.table)
  10. .where(this.getConditions(aggregationRequest));
  11. BlazeJPAQuery<AggregationResultRow> ageSelect = new BlazeJPAQuery<AggregationResultRow>(entityManager, criteriaBuilderFactory)
  12. .with(this.aggregationValues, filteredValues)
  13. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.age.as("value"),
  14. this.aggregationValues.count().as("row_count"),
  15. Expressions.asString("age").as("column_name")))
  16. .from(this.aggregationValues)
  17. .groupBy(this.aggregationValues.age);
  18. BlazeJPAQuery<AggregationResultRow> genderSelect = new BlazeJPAQuery<AggregationResultRow>(entityManager, criteriaBuilderFactory)
  19. .with(this.aggregationValues, filteredValues)
  20. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.gender.as("value"),
  21. this.aggregationValues.count().as("row_count"),
  22. Expressions.asString("gender").as("column_name")))
  23. .from(this.aggregationValues)
  24. .groupBy(this.aggregationValues.gender);
  25. BlazeJPAQuery<AggregationResultRow> mainCitySelect = new BlazeJPAQuery<AggregationResultRow>(entityManager, criteriaBuilderFactory)
  26. .with(this.aggregationValues, filteredValues)
  27. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.mainCity.as("value"),
  28. this.aggregationValues.count().as("row_count"),
  29. Expressions.asString("main_city").as("column_name")))
  30. .from(this.aggregationValues)
  31. .groupBy(this.aggregationValues.mainCity);
  32. return ageSelect.unionAll(genderSelect, mainCitySelect).fetch();
  33. }

请注意,这只是代码的翻译部分,不包括其他内容。如果您有任何其他问题,请随时提出。

英文:

I'm using Oracle DB and has Students table:

Students Table:

  1. | COLUMN | TYPE |
  2. | ----------- | ------------- |
  3. | ID | VARCHAR2(200) |
  4. | NAME | VARCHAR2(200) |
  5. | AGE | NUMBER(5) |
  6. | MAIN_CITY | VARCHAR2(200) |
  7. | GENDER | VARCHAR2(50) |
  8. | SCORE | FLOAT(5) |

`

I'm trying to convert this SQL query to query-dsl code:

  1. SELECT /*+ parallel(2)*/ *
  2. FROM (WITH filtered_values(age, gender, main_city) AS
  3. (
  4. SELECT /*+ MATERIALIZE */ age, gender, main_city
  5. FROM Students
  6. -- GET CONDITIONS FROM USER AND FILTER THE QUERY USING WHERE
  7. )
  8. SELECT *
  9. FROM (
  10. SELECT age AS value, COUNT(*) AS row_count, &#39;age&#39; AS column_name
  11. FROM filtered_values
  12. GROUP BY age
  13. ORDER BY row_count)
  14. WHERE rownum &lt;= 5
  15. UNION ALL (
  16. SELECT *
  17. FROM (
  18. SELECT gender AS value, COUNT(*) AS row_count, &#39;gender&#39; AS column_name
  19. FROM filtered_values
  20. GROUP BY gender
  21. ORDER BY row_count)
  22. WHERE rownum &lt;= 5)
  23. UNION ALL (
  24. SELECT *
  25. FROM (
  26. SELECT main_city AS value, COUNT(*) AS row_count, &#39;main_city&#39; AS column_name
  27. FROM filtered_values
  28. GROUP BY main_city
  29. ORDER BY row_count)
  30. WHERE rownum &lt;= 5)
  31. )

The filters that available from client is flexible and change the WITH query, for example:

where score greater than 20:
> WITH filtered_values(age, gender, main_city) AS
> (
> SELECT /*+ MATERIALIZE */ age, gender, main_city
> FROM Students
> WHERE score > 20
> )

where city is LA or NYC, and score is between 50-60:
> WITH filtered_values(age, gender, main_city) AS
> (
> SELECT /*+ MATERIALIZE */ age, gender, main_city
> FROM Students
> WHERE main_city IN ('LA', 'NYC') AND score >= 50 AND score <= 60
> )

I'm using QueryDsl version 5.0.0.

I've created Java classes:

Student:

  1. @Data
  2. @Entity
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. @Table(schema = &quot;PROD&quot;, name = &quot;Students&quot;)
  6. public class Student implements Serializable {
  7. @Id
  8. @Column(name = &quot;ID&quot;)
  9. private String id;
  10. @Column(name = &quot;NAME&quot;)
  11. private String name;
  12. @Column(name = &quot;AGE&quot;)
  13. private int age;
  14. @Column(name = &quot;MAIN_CITY&quot;)
  15. private String mainCity;
  16. @Column(name = &quot;SCORE&quot;)
  17. private float score;
  18. }

AggregationValues:

  1. @Data
  2. @Entity
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. @Table(schema = &quot;PROD&quot;, name = &quot;NOT_REAL_TABLE&quot;)
  6. public class AggregationValues {
  7. private int age;
  8. private String gender;
  9. private String mainCity;
  10. }

AggregationResultRow:

  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. public class AggregationResultRow {
  5. private String value;
  6. private long rowCount;
  7. private String columnName;
  8. }

My code is:
> Note that this.getConditions(aggregationsRequest) return BooleanBuilder with all the filters from the client.

  1. private final QStudent table = QStudent.student;
  2. private final QAggregationValues aggregationValues = QAggregationValues.aggregationValues;
  3. public List&lt;AggregationResultRow&gt; getAggergations(AggregationRequest aggregationRequest) {
  4. SubQueryExpression&lt;AggregationValues&gt; filteredValues = new BlazeJPAQuery&lt;AggregationValues&gt;(entityManager, criteriaBuilderFactory)
  5. .select(Projections.constructor(AggregationValues.class,
  6. this.table.age,
  7. this.table.gender,
  8. this.table.mainCity))
  9. .from(this.table)
  10. .where(this.getConditions(aggregationRequest));
  11. BlazeJPAQuery&lt;AggregationResultRow&gt; ageSelect = new BlazeJPAQuery&lt;AggregationResultRow&gt;(entityManager, criteriaBuilderFactory)
  12. .with(this.aggregationValues, filteredValues)
  13. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.age.as(&quot;value&quot;),
  14. this.aggregationValues.count().as(&quot;row_count&quot;),
  15. Expressions.asString(&quot;age&quot;).as(&quot;column_name&quot;)))
  16. .from(this.aggregationValues)
  17. .groupBy(this.aggregationValues.age);
  18. BlazeJPAQuery&lt;AggregationResultRow&gt; genderSelect = new BlazeJPAQuery&lt;AggregationResultRow&gt;(entityManager, criteriaBuilderFactory)
  19. .with(this.aggregationValues, filteredValues)
  20. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.gender.as(&quot;value&quot;),
  21. this.aggregationValues.count().as(&quot;row_count&quot;),
  22. Expressions.asString(&quot;gender&quot;).as(&quot;column_name&quot;)))
  23. .from(this.aggregationValues)
  24. .groupBy(this.aggregationValues.gender);
  25. BlazeJPAQuery&lt;AggregationResultRow&gt; mainCitySelect = new BlazeJPAQuery&lt;AggregationResultRow&gt;(entityManager, criteriaBuilderFactory)
  26. .with(this.aggregationValues, filteredValues)
  27. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.mainCity.as(&quot;value&quot;),
  28. this.aggregationValues.count().as(&quot;row_count&quot;),
  29. Expressions.asString(&quot;main_city&quot;).as(&quot;column_name&quot;)))
  30. .from(this.aggregationValues)
  31. .groupBy(this.aggregationValues.mainCity);
  32. return ageSelect.unionAll(genderSelect, mainCitySelect).fetch();
  33. }

But I got Exception - java.lang.IllegalArgumentException: Don&#39;t mix union and from

I've tried more code ideas but nothing works and this one looks the closest to my query.

Any ideas?

Thank you very much, I'll appreciate it a lot!

答案1

得分: 0

这是您提供的代码的中文翻译部分:

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

  1. @Autowired
  2. private JdbcTemplate jdbcTemplate;

这是该函数:

  1. public List<AggregationResultRow> getAggregations(AggregationRequest aggregationRequest) throw Exception {
  2. Connection connection = this.jdbcTemplate.getDataSource().getConnection();
  3. OracleQuery<AggregationResultRow> query = new OracleQuery<AggregationResultRow>(connection)
  4. .with(this.aggregationValues, new OracleQuery<AggregationValues>(connection)
  5. .select(Projections.constructor(AggregationValues.class, this.table.age.as(this.aggregationValues.age), this.table.gender.as(this.aggregationValues.gender),
  6. this.table.mainCity.as(this.aggregationValues.mainCity)))
  7. .from(this.table)
  8. where(this.getConditions(aggregationRequest)));
  9. query.unionAll(new OracleQuery<AggregationResultRow>(connection)
  10. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.age.as("value"),
  11. this.aggregationValues.age.count().as("row_count"),
  12. Expressions.asString("age").as("column_name")))
  13. .from(this.aggregationValues)
  14. .groupBy(this.aggregationValues.age),
  15. new OracleQuery<AggregationResultRow>(connection)
  16. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.gender.as("value"),
  17. this.aggregationValues.gender.count().as("row_count"),
  18. Expressions.asString("gender").as("column_name")))
  19. .from(this.aggregationValues)
  20. .groupBy(this.aggregationValues.gender),
  21. new OracleQuery<AggregationResultRow>(connection)
  22. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.mainCity.as("value"),
  23. this.aggregationValues.mainCity.count().as("row_count"),
  24. Expressions.asString("mainCity").as("column_name")))
  25. .from(this.aggregationValues)
  26. .groupBy(this.aggregationValues.mainCity));
  27. return query.fetch();
  28. }

现在,我只需要在WITH子句的select中添加Materialize,并并行执行所有函数。有任何想法吗?

英文:

So I found a half way solution!
What I’ve done is to add autowired parameter in class:

  1. @Autowired
  2. private JdbcTemplate jdbcTemplate;

And this is the function:

  1. public List&lt;AggregationResultRow&gt; getAggregations(AggregationRequest aggregationRequest) throw Exception {
  2. Connection connection = this.jdbcTemplate.getDataSource().getConnection();
  3. OracleQuery&lt;AggregationResultRow&gt; query = new OracleQuery&lt;AggregationResultRow&gt;(connection)
  4. .with(this.aggregationValues, new OracleQuery&lt;AggregationValues&gt;(connection)
  5. .select(Projections.constructor(AggregationValues.class, this.table.age.as(this.aggregationValues.age), this.table.gender.as(this.aggregationValues.gender),
  6. this.table.mainCity.as(this.aggregationValues.mainCity)))
  7. .from(this.table)
  8. where(this.getConditions(aggregationRequest)));
  9. query.unionAll(new OracleQuery&lt;AggregationResultRow&gt;(connection)
  10. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.age.as(“value”),
  11. this.aggregationValues.age.count().as(“row_count”),
  12. Expressions.asString(“age”).as(“column_name”)))
  13. .from(this.aggregationValues)
  14. .groupBy(this.aggregationValues.age),
  15. new OracleQuery&lt;AggregationResultRow&gt;(connection)
  16. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.gender.as(“value”),
  17. this.aggregationValues.gender.count().as(“row_count”),
  18. Expressions.asString(“gender”).as(“column_name”)))
  19. .from(this.aggregationValues)
  20. .groupBy(this.aggregationValues.gender),
  21. new OracleQuery&lt;AggregationResultRow&gt;(connection)
  22. .select(Projections.constructor(AggregationResultRow.class, this.aggregationValues.mainCity.as(“value”),
  23. this.aggregationValues.mainCity.count().as(“row_count”),
  24. Expressions.asString(“mainCity”).as(“column_name”)))
  25. .from(this.aggregationValues)
  26. .groupBy(this.aggregationValues.mainCity));
  27. return query.fetch();
  28. }

Now I only need to add Materialize to the select in the WITH clause and parallel to all the function. Any ideas?

huangapple
  • 本文由 发表于 2023年2月27日 17:38:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/75578795.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定