OFFSET N FETCH FIRST M ROWS 与 JDBC 和 PostgreSQL 不工作

Posted

技术标签:

【中文标题】OFFSET N FETCH FIRST M ROWS 与 JDBC 和 PostgreSQL 不工作【英文标题】:OFFSET N FETCH FIRST M ROWS with JDBC and PostgreSQL not working 【发布时间】:2018-05-16 13:04:33 【问题描述】:

我正在尝试使用 JDBC 和 PostgreSQL 进行查询,但我遇到了在任何文档中都找不到的奇怪情况。

如果我通过 pgAdmin 和 H2(我将其用于我的应用程序的单元测试)执行以下查询,则以下查询有效,但如果我通过 JDBC 执行它,则会出现语法错误:

Queries.SELECT_SQL

SELECT columns 
  FROM Table 
  LEFT JOIN TableToJoin1 
  LEFT JOIN TableToJoin2 
  LEFT JOIN TableToJoin3 
  JOIN TableToJoin4

Queries.ENDING_PAGING_STATEMENT_SQL

OFFSET ? ROWS FETCH FIRST ? ROWS ONLY

SELECT 查询是正确的,并且可以使用任何方式正常工作,问题是当我将两个查询放在一起时,即 SELECT 语句以及 OFFSETFETCH FIRST

这就是我通过JDBC 执行查询的方式:

// Receive offset and limit as argument.
try (final PreparedStatement selectStatement = connection
        .prepareStatement(Queries.SELECT_SQL + Queries.ENDING_PAGING_STATEMENT_SQL)) 

  selectStatement.setInt(Queries.PAGING_ENDING_STATEMENT_OFFSET_ARGUMENT_POSITION, offset);
  selectStatement.setInt(Queries.PAGING_ENDING_STATEMENT_LIMIT_ARGUMENT_POSITION, limit);

  final ResultSet resultSet = bookSelectStatement.executeQuery();
  ...

这里是抛出异常的消息:

org.postgresql.util.PSQLException: ERROR: syntax error at or near "$2"

如果我调用selectStatement.toString() 进行调试,我会收到完全符合我预期的查询。

如果我将OFFSET N ROWS FETCH FIRST M ROWS ONLY 更改为OFFSET N LIMIT M,它将通过JDBC 正常工作。 最简单的解决方案是在上面进行简单的更改,但我的部分任务是使用此 FETCH FIRST M ROWS ONLY 语句进行查询。

那么,你们能帮我看看我是否做错了,或者根本没有办法在 JDBC for PostgreSQL 上使用FETCH FIRST?提供一些示例或对任何有帮助的文档的一些参考。

我注意到FETCH FIRST 在PostgreSQL Documentation: Queries - Offset and Limit 上不存在,但由于它通过 pgAdmin 工作,我不知道为什么我在使用 JDBC 时会遇到任何问题。

非常感谢!

【问题讨论】:

fetch first 是关于 select statement 的章节中的文档 - 看起来像文档错误 您也不能在PreparedStatement 中提供限制/偏移作为可分配参数。实际上,这可能不再适用,取决于驱动程序。 谢谢@a_horse_with_no_name,它被隐藏在索引中,但看起来我对查询没有做错任何事情。 @Kayaman,但是如果我将OFFSET N ROWS FETCH FIRST M ROWS ONLY 更改为OFFSET N LIMIT M 它将正常工作,而无需更改PreparedStatement 上的任何内容,为什么会有所不同? 看来PreparedStatement 确实允许参数化限制/偏移,但我可以发誓我之前遇到过问题。我可能正在考虑一些不允许这样做的混淆层。 【参考方案1】:

我可以重现这个问题。从版本 10 开始,documentation 表示:

在这种语法中,要编写除简单整数常量之外的任何内容作为开始或计数,您必须在其周围加上括号

当然,这很荒谬。应该允许不带括号的绑定变量 - 大多数数据库都允许它们并且 PostgreSQL 也接受 OFFSET ? LIMIT ? 语法,但看起来好像它们不在 PostgreSQL 对标准 SQL 语法的解释中。所以你必须写:

OFFSET (?) ROWS FETCH FIRST (?) ROWS ONLY

I would consider this a bug, which I've reported here

【讨论】:

哎呀,我正在使用它,我只是忘记写在问题上,谢谢。但不管有没有那个关键字,它都会给我同样的错误。 什么?好的.. 这真的很有帮助,我在上课时没有任何笔记,所以这是新的,出乎意料的。谢谢,现在可以正常使用了! “看起来好像它们不在标准 SQL 语法中” SQL 标准允许文字或参数(但不允许列等),但它不允许允许表达式。从技术上讲,标准甚至不允许使用括号。 (SQL:2016-2 7.17) @a_horse_with_no_name:我已恢复您的更改并添加了清晰的版本指示器。我认为这是一个应该修复的错误,所以将来,手册可能会说一些不同的内容 @MarkRotteveel:是的,修正了我的措辞。我不是这个意思

以上是关于OFFSET N FETCH FIRST M ROWS 与 JDBC 和 PostgreSQL 不工作的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server ->> OFFSET & FETCH子句

OFFSET FETCH NEXT知识点整合

OFFSET ... FETCH 在高分页值时很慢

为啥我不能在我的 SQL Server 上查询 OFFSET/FETCH 查询?

SQL Server 2005相当于OFFSET / FETCH [重复]

sql SELECT TOP,OFFSET,FETCH.sql