Spring Boot中的本机查询,列表中元组的WHERE条件

Posted

技术标签:

【中文标题】Spring Boot中的本机查询,列表中元组的WHERE条件【英文标题】:Native query in Spring Boot with WHERE condition for tuple in list 【发布时间】:2019-08-14 09:27:40 【问题描述】:

当向 PostgreSQL 发送普通 SQL 时,如下所示:

CREATE TABLE things (
    id      BIGINT PRIMARY KEY NOT NULL,
    foo     BIGINT NOT NULL,
    bar     BIGINT NOT NULL
);


INSERT INTO things VALUES (9900, 1, 2);
INSERT INTO things VALUES (9901, 3, 4);
INSERT INTO things VALUES (9902, 1, 4);
SELECT * FROM things WHERE foo IN (1, 2);
SELECT * FROM things WHERE (foo, bar) IN (VALUES (1, 2), (3, 4));

它按预期工作。

但是,当尝试使用 Spring Boot 做同样的事情时,它会失败。这是我的最小示例(Kotlin):

实体:

import org.springframework.data.jpa.domain.AbstractPersistable
import javax.persistence.Entity
import javax.persistence.Table

@Entity
@Table(name = "things")
class Thing(
        val foo: Long,
        val bar: Long
) : AbstractPersistable<Long>()

存储库:

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query

interface ThingRepository : JpaRepository<Thing, Long> 

    @Query(nativeQuery = true, value = "SELECT * FROM things WHERE foo IN (1, 2);")
    fun selectNativeByFoo(): Iterable<Thing>

    @Query(nativeQuery = true, value = "SELECT * FROM things WHERE (foo, bar) IN (VALUES (1, 2), (3, 4));")
    fun selectNativeByFooAndBar(): Iterable<Thing>

调用selectNativeByFoo 工作正常,但调用selectNativeByFooAndBar 失败,并出现以下异常:

org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [SELECT * FROM things WHERE (foo, bar) IN (VALUES (1, 2), (3, 4));]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement


Caused by: org.h2.jdbc.JdbcSQLException: Invalid parameter count for "VALUES", expected count: "1"; SQL statement:
SELECT * FROM things WHERE (foo, bar) IN (VALUES (1, 2), (3, 4)); [7001-197]

我做错了什么?

【问题讨论】:

在您的 SQL 实验中,您使用的是 PostgreSQL。在您的异常中,异常是 org.h2.jdbc.JdbcSQLException,表明您使用的不是 PostgreSQL,而是 H2。我的猜测是您的实际生产数据库是 PostgreSQL。因此,我会针对 PostgreSQL 而不是 H2 运行测试。 @JBNizet 谢谢,你是绝对正确的。我正在使用 H2。但是在我的application.yaml 中,我有spring.datasource.url: jdbc:h2:mem:db;MODE=PostgreSQL,并且我(可能过于天真)假设,这足以使其以兼容的方式工作。 用实物测试一下。我的猜测是,确实,你太天真了:-) 【参考方案1】:

感谢JB Nizet 的this comment,我能够解决它。

使用的语法

SELECT * FROM things WHERE (foo, bar) IN (VALUES (1, 2), (3, 4));

只有真正的 PostgreSQL 支持,而不是 H2,我在测试中使用它,即使是

spring.datasource.url: jdbc:h2:mem:db;MODE=PostgreSQL

改成

SELECT * FROM things WHERE (foo, bar) IN ((1, 2), (3, 4));

使其在 Postgres 模式下同时在真正的 Postgres 和 H2 中工作。


另一个选择是切换到embedded-database-spring-test 并使用它的嵌入式 Postgres 进行测试。那么原始语法(使用VALUES)也可以使用。

【讨论】:

以上是关于Spring Boot中的本机查询,列表中元组的WHERE条件的主要内容,如果未能解决你的问题,请参考以下文章

关于Python中元组的问题

如何访问列表中元组的第一个元素?

获取包含元组的列表的索引,其中元组的第一个元素与模式匹配

使用带有 LIKE 的 mysql 本机查询的 spring boot 搜索返回空

我如何获得haskell中元组的索引?

如何根据postgres的jsonb列的where条件(无本机查询)使用jpa在spring boot中选择数据?