无效的列名异常 - 使用别名的 JdbcPagingItemReader 查询

Posted

技术标签:

【中文标题】无效的列名异常 - 使用别名的 JdbcPagingItemReader 查询【英文标题】:Invalid column name exception - JdbcPagingItemReader query with alias 【发布时间】:2018-09-20 13:57:53 【问题描述】:

当 JdbcPagingItemReader 查询具有连接和别名时,Spring 批处理步骤失败。当我删除连接并从员工表中进行简单查询时,它工作正常。下面是失败的代码 sn-p。有没有人遇到过这样的问题?任何帮助,将不胜感激。

spring-batch-core-4.0.1.RELEASE spring-boot-2.0.0.RELEASE

@Autowired
    @Bean(destroyMethod = "")
    @StepScope
    public JdbcPagingItemReader<String> dbItemReader(final DataSource dataSource, final PreparedStatementSetter paramSetter) 
         return new JdbcPagingItemReaderBuilder<String>().name("dbReader").dataSource(dataSource)            .queryProvider(queryProvider(prodDataSource)).rowMapper((rs, rowNum) -> 
         return rs.getString("first_name");
         ).pageSize(1000).fetchSize(1000).build();
    

@Bean
public PagingQueryProvider queryProvider(final DataSource dataSource) 
    final OraclePagingQueryProvider provider = new OraclePagingQueryProvider();
    provider.setSelectClause("select first_name");
    provider.setFromClause("from employee e join department d on e.dept_no= d.dept_no");
    provider.setWhereClause("where d.dept_name in ('HR','Marketing')");
    final Map<String, Order> sortKeys = new HashMap<String, Order>();
    sortKeys.put("e.dept_no", Order.ASCENDING);
    sortKeys.put("e.employee_id", Order.ASCENDING);
    provider.setSortKeys(sortKeys);
    try 
        return provider;
     catch (final Exception e) 
        e.printStackTrace();
        return null;
    

原因:java.sql.SQLException: Invalid column name at oracle.jdbc.driver.OracleStatement.getColumnIndex(OracleStatement.java:3965) ~[ojdbc6-11.2.0.3.jar:12.1.0.1.0] 在 oracle.jdbc.driver.InsensitiveScrollableResultSet.findColumn(InsensitiveScrollableResultSet.java:299) ~[ojdbc6-11.2.0.3.jar:12.1.0.1.0] 在 oracle.jdbc.driver.GeneratedResultSet.getObject(GeneratedResultSet.java:1394) ~[ojdbc6-11.2.0.3.jar:12.1.0.1.0] 在 org.apache.commons.dbcp.DelegatingResultSet.getObject(DelegatingResultSet.java:328) ~[commons-dbcp-1.4.jar:1.4] 在 org.apache.commons.dbcp.DelegatingResultSet.getObject(DelegatingResultSet.java:328) ~[commons-dbcp-1.4.jar:1.4] 在 org.springframework.batch.item.database.JdbcPagingItemReader$PagingRowMapper.mapRow(JdbcPagingItemReader.java:333) ~[spring-batch-infrastructure-4.0.0.RELEASE.jar:4.0.0.RELEASE] 在 org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:93) ~[spring-jdbc-5.0.4.RELEASE.jar:5.0.4.RELEASE] 在 org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:60) ~[spring-jdbc-5.0.4.RELEASE.jar:5.0.4.RELEASE] 在 org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:667) ~[spring-jdbc-5.0.4.RELEASE.jar:5.0.4.RELEASE] 在 org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605) ~[spring-jdbc-5.0.4.RELEASE.jar:5.0.4.RELEASE] ... 72个常用框架 省略

【问题讨论】:

【参考方案1】:

几年后,我偶然发现了同样的问题。 我想给出正确答案,因为这里没有完全设置正确的答案。

@Bean
public PagingQueryProvider queryProvider(final DataSource dataSource) 
    final OraclePagingQueryProvider provider = new OraclePagingQueryProvider();
    provider.setSelectClause("select e.first_name, e.dept_no as dept_no, e.employee_id as employee_id");
    provider.setFromClause("from employee e join department d on e.dept_no= d.dept_no");
    provider.setWhereClause("where d.dept_name in ('HR','Marketing')");
    final Map<String, Order> sortKeys = new HashMap<String, Order>();
    sortKeys.put("dept_no", Order.ASCENDING);
    sortKeys.put("employee_id", Order.ASCENDING);
    provider.setSortKeys(sortKeys);
    try 
        return provider;
     catch (final Exception e) 
        e.printStackTrace();
        return null;
    

那么发生了什么变化:

e.dept_no as dept_no, e.employee_id as employee_id 被添加到选择查询中。 sortKeys.put 不能使用别名。 问题是 sortKeys 将从结果列表中检索数据。 如果您设置了别名 =>,则行映射器会尝试获取 alias.column_name,但由于结果集不包含别名,因此该名称不存在。 因此,我们还在选择查询中默认添加AS,以避免列名模棱两可。

【讨论】:

【参考方案2】:

不要在你的 SortKeys 顺序上使用这个(e.)-point- 通过 experssion,它会很好

【讨论】:

【参考方案3】:

我敢打赌,使用 JOIN 是行不通的,因为它是页面项目阅读器。它需要一个一致的列表和主键来处理。您可以尝试将您的 JOIN 创建为具有自己唯一主键的视图,并针对该视图运行您的简单查询。

【讨论】:

感谢 BrianC。它有帮助【参考方案4】:

我已经在这里回答了对我有用的问题 - https://***.com/a/70357862/1909708。

我确实在排序子句中使用了列别名,并且该列别名与列名(包括表别名)保持相同。

这是 Spring Batch 中的一个现有问题 - https://github.com/spring-projects/spring-batch/issues/1208

【讨论】:

以上是关于无效的列名异常 - 使用别名的 JdbcPagingItemReader 查询的主要内容,如果未能解决你的问题,请参考以下文章

计算列上的 T-SQL 列别名 - 列名无效

异常“列名无效”[重复]

所有列名无效

为啥我会收到“无效的列名”?消息 207 级别 16 状态 1 第 14 行

System.Data.Entity.Core.EntityCommandExecutionException 和内部异常 SqlException:无效的列名“xxxx”

数据库表上的列名无效