Spring 以列别名作为排序键的批处理 - 格式错误的 "where" 语句

Spring batch with column alias as sort key - malformed "where" statement

我正在使用 Spring-批处理版本 3.0。6.RELEASE 查询 MySQL 数据库中的一些数据,然后对其进行处理。

使用详情:

查询:

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"。与嵌套查询相比,我们更喜欢这种方法。