Spring 以列别名作为排序键的批处理 - 格式错误的 "where" 语句
Spring batch with column alias as sort key - malformed "where" statement
我正在使用 Spring-批处理版本 3.0。6.RELEASE 查询 MySQL 数据库中的一些数据,然后对其进行处理。
使用详情:
- 查询提供商是
MySqlPagingQueryProvider
- 在设置查询提供程序时,我将查询中的其中一列的别名指定为
sort key
(请查看下面的查询以获取更多详细信息)
查询:
SELECT
target.tx_timestamp AS event_datetime,
....
FROM
some_table AS target
....
WHERE
target.tx_timestamp > :startTime AND target.tx_timestamp <= :endTime;
代码:
Map<String, Order> sortKeys = new HashMap<>();
sortKeys.put("event_datetime", Order.ASCENDING);
MySqlPagingQueryProvider queryProvider = new MySqlPagingQueryProvider();
queryProvider.setSortKeys(sortKeys);
生成的查询(请注意带event_datetime的部分):
WHERE
(target.tx_timestamp > ? AND target.tx_timestamp <= ?) AND
((event_datetime > ?))
错误:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar .... Unknown column 'event_datetime' in 'where clause'.
是否可以使用别名作为排序键?
另外值得注意的是 this thread with same issue and this Spring batch Jira ticket,它被标记为已解决版本 3.0.4。
我也尝试过使用 3.0.4.RELEASE、3.0.5.RELEASE 和 3.0.7.RELEASE 版本,结果相同。
编辑:
再尝试几次后,我可以补充说,只有当有足够的记录超过一页时,问题才会出现。第一页的查询顺利通过,但后续页面的查询失败。
编辑2:
正如 Sabir 所指出的,问题实际上与 where 子句中的列别名有关。 Spring 在这种情况下批处理工作正常。
对于遇到相同问题的 运行 人:
您可以通过将整个查询嵌套在另一个 select 中来解决此问题,如下所示:
SELECT * FROM (
SELECT
target.tx_timestamp AS event_datetime,
....
FROM
some_table AS target
....
WHERE
target.tx_timestamp > :startTime AND target.tx_timestamp <= :endTime) our_inner_select;
在我发布问题时我不知道,别名不能在 WHERE 子句中使用,因为 spring 批次被赋予别名 event_datetime
作为排序键,块的查询在第一个基于排序键的附加条件生成之后。
对于上面的查询,内部 select 在 spring 批处理添加 WHERE 条件之前被评估,然后可以使用列别名作为排序键。
当您将 SELECT 的列别名指定为排序键时,page - 1(即 page -0 除外) 由 Spring 生成的后续查询如问题中所示在 WHERE 子句中批量使用该别名,并且根据 this SO question ,如果评估 SELECT 子句,则不允许在 WHERE 子句中使用列别名不强制在 WHERE 子句之前。
所以回答你的问题 - 不,你不能使用别名作为排序键,除非你按照其他 SQL 问题中的建议强制执行别名评估。
我们 运行 解决了这个问题,Spring 必须从返回的结果集中获取您的排序键才能正确分页。正如前面的回答所解释的,排序键在 WHERE 子句中使用,该子句不适用于列别名。
我们的解决方案是 SELECT target.tx_timestamp as "target.tx_timestamp"
以便可以使用相同的名称从结果集中检索排序键。执行 SELECT target.tx_timestamp
会将列 tx_timestamp 放入您的结果集中,这会导致问题,因为您的排序键需要是 "target.tx_timestamp"。与嵌套查询相比,我们更喜欢这种方法。
我正在使用 Spring-批处理版本 3.0。6.RELEASE 查询 MySQL 数据库中的一些数据,然后对其进行处理。
使用详情:
- 查询提供商是
MySqlPagingQueryProvider
- 在设置查询提供程序时,我将查询中的其中一列的别名指定为
sort key
(请查看下面的查询以获取更多详细信息)
查询:
SELECT
target.tx_timestamp AS event_datetime,
....
FROM
some_table AS target
....
WHERE
target.tx_timestamp > :startTime AND target.tx_timestamp <= :endTime;
代码:
Map<String, Order> sortKeys = new HashMap<>();
sortKeys.put("event_datetime", Order.ASCENDING);
MySqlPagingQueryProvider queryProvider = new MySqlPagingQueryProvider();
queryProvider.setSortKeys(sortKeys);
生成的查询(请注意带event_datetime的部分):
WHERE
(target.tx_timestamp > ? AND target.tx_timestamp <= ?) AND
((event_datetime > ?))
错误:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar .... Unknown column 'event_datetime' in 'where clause'.
是否可以使用别名作为排序键?
另外值得注意的是 this thread with same issue and this Spring batch Jira ticket,它被标记为已解决版本 3.0.4。
我也尝试过使用 3.0.4.RELEASE、3.0.5.RELEASE 和 3.0.7.RELEASE 版本,结果相同。
编辑: 再尝试几次后,我可以补充说,只有当有足够的记录超过一页时,问题才会出现。第一页的查询顺利通过,但后续页面的查询失败。
编辑2: 正如 Sabir 所指出的,问题实际上与 where 子句中的列别名有关。 Spring 在这种情况下批处理工作正常。
对于遇到相同问题的 运行 人: 您可以通过将整个查询嵌套在另一个 select 中来解决此问题,如下所示:
SELECT * FROM (
SELECT
target.tx_timestamp AS event_datetime,
....
FROM
some_table AS target
....
WHERE
target.tx_timestamp > :startTime AND target.tx_timestamp <= :endTime) our_inner_select;
在我发布问题时我不知道,别名不能在 WHERE 子句中使用,因为 spring 批次被赋予别名 event_datetime
作为排序键,块的查询在第一个基于排序键的附加条件生成之后。
对于上面的查询,内部 select 在 spring 批处理添加 WHERE 条件之前被评估,然后可以使用列别名作为排序键。
当您将 SELECT 的列别名指定为排序键时,page - 1(即 page -0 除外) 由 Spring 生成的后续查询如问题中所示在 WHERE 子句中批量使用该别名,并且根据 this SO question ,如果评估 SELECT 子句,则不允许在 WHERE 子句中使用列别名不强制在 WHERE 子句之前。
所以回答你的问题 - 不,你不能使用别名作为排序键,除非你按照其他 SQL 问题中的建议强制执行别名评估。
我们 运行 解决了这个问题,Spring 必须从返回的结果集中获取您的排序键才能正确分页。正如前面的回答所解释的,排序键在 WHERE 子句中使用,该子句不适用于列别名。
我们的解决方案是 SELECT target.tx_timestamp as "target.tx_timestamp"
以便可以使用相同的名称从结果集中检索排序键。执行 SELECT target.tx_timestamp
会将列 tx_timestamp 放入您的结果集中,这会导致问题,因为您的排序键需要是 "target.tx_timestamp"。与嵌套查询相比,我们更喜欢这种方法。