Spring - JdbcTemplate - 使用CTE和枚举行进行查询

时间:2017-03-09 19:10:12

标签: java sql spring postgresql jdbctemplate

我正在尝试创建一个使用CTE结构的查询。查询如下所示:

with data (a, b, c) as (
    values  ('a1', 'b1', 'c1'), ('a2', 'b2', 'c2')
)
select * from data

这个查询当然是简化的,为了保持这一点。

以下效果很好:

@Component
public class QueryTest {
    private NamedParameterJdbcTemplate template;

    @Autowired
    public QueryTest(final DataSource source) {
        template = new NamedParameterJdbcTemplate(source);
    }

    @Scheduled(fixedRate = 1000)
    public void test() {
        MapSqlParameterSource p = new MapSqlParameterSource()
                .addValue("data", Arrays.asList(
                        new Object[]{"a1", "b1", "c1"},
                        new Object[]{"a2", "b2", "c2"}));
        System.out.println(template.query("with data (a, b, c) as (values :data) select * from data", p, (set, index) -> new Object()));
    }
}

但是,如果我在data命名参数中只有一行,则它不起作用:

@Component
public class QueryTest {
    private NamedParameterJdbcTemplate template;

    @Autowired
    public QueryTest(final DataSource source) {
        template = new NamedParameterJdbcTemplate(source);
    }

    @Scheduled(fixedRate = 1000)
    public void test() {
        MapSqlParameterSource p = new MapSqlParameterSource()
                .addValue("data", Arrays.asList(
                        new Object[]{"a1", "b1", "c1"}));
        System.out.println(template.query("with data (a, b, c) as (values :data) select * from data", p, (set, index) -> new Object()));
    }
}

我收到以下错误:

Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "$1"
  Position: 32
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2284) ~[postgresql-9.4.1208.jar:9.4.1208]
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2003) ~[postgresql-9.4.1208.jar:9.4.1208]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:200) ~[postgresql-9.4.1208.jar:9.4.1208]
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:424) ~[postgresql-9.4.1208.jar:9.4.1208]
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:161) ~[postgresql-9.4.1208.jar:9.4.1208]
    at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:114) ~[postgresql-9.4.1208.jar:9.4.1208]
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-2.5.1.jar:?]
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-2.5.1.jar:?]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:688) ~[spring-jdbc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:629) ~[spring-jdbc-4.2.5.RELEASE.jar:4.2.5.RELEASE]

知道这里出了什么问题吗?有没有更好的方法来执行这些类型的查询?

更新

我在postgres中启用了日志记录,看起来第一个查询被解析为:

with data (a, b, c) as (values ($1, $2, $3), ($4, $5, $6)) select * from data

但第二个被解决为:

with data (a, b, c) as (values $1, $2, $3) select * from data

看起来周围的括号丢失了吗?

1 个答案:

答案 0 :(得分:0)

问题在于您使用Arrays.asList。传入多个对象数组时,您将获得一个对象数组列表。如果只传入单个对象数组,则会获得数组内容的列表,而不是单个对象数组的列表。它将数组解释为单独的varargs而不是一个参数。如果您打印出Arrays.asList(new Object[]{"a1", "b1", "c1"})给出的内容,它将如下所示:[a1,b1,c1]。

对于单个数组用例,请尝试使用Collections.singletonList创建列表,或者创建ArrayList,然后使用add方法添加数据值。

MapSqlParameterSource p = new MapSqlParameterSource() .addValue("data", Collections.singletonList(new Object[]{"a1", "b1", "c1"}));