简体   繁体   English

Spring JPA / Hibernate本机查询(PostgreSQL)中的单引号参数值

[英]Single-quoting parameter values in Spring JPA/Hibernate Native query (PostgreSQL)

I have a database that stores an event in an "event" table, with multiple readings for that event stored in a "reading" table, with a foreign key of the event id. 我有一个数据库,该数据库将事件存储在“事件”表中,该事件的多个读数存储在“读取”表中,并带有事件ID的外键。 The event itself has a timestamp stored in UTC (Timestamp with Time Zone). 事件本身具有存储在UTC中的时间戳(带有时区的时间戳)。 I have users however in multiple time zones, and want to summarize the readings on a given day, in the user's timezone. 但是,我有多个时区的用户,并希望在该用户的时区中总结给定日期的读数。

I'm able to successfully query to retrieve the maximum, minimum and average reading for a given day (utc) using a native query: 我能够使用本机查询成功查询以检索给定日期(utc)的最大,最小和平均读数:

@Query(nativeQuery=true, value="SELECT source, to_char(timestamp, 'yyyy-MM-dd') as \"date\", min(decimalreading), max(decimalreading), avg(decimalreading) " +
                "FROM reading, event " +
                "WHERE reading.event = event.id and source = ?1 "+
                "and timestamp between ?2 and ?3 "+
                "GROUP BY event.source, to_char(timestamp, 'yyyy-MM-dd') " +
                "ORDER BY source, to_char(timestamp, 'yyyy-MM-dd')")
List<Object[]> minMax(long source, Calendar from, Calendar to);

Postgres nicely supports the "timestamp at time zone" syntax, so I tried: Postgres很好地支持“时区的时间戳”语法,所以我尝试了:

@Query(nativeQuery=true, value="SELECT source, to_char(timestamp at time zone ?4, 'yyyy-MM-dd') as \"date\", min(decimalreading), max(decimalreading), avg(decimalreading) " +
                "FROM reading, event " +
                "WHERE reading.event = event.id and source = ?1 " +
                "and timestamp at time zone ?4 between ?2 and ?3 "+
                "GROUP BY event.source, to_char(timestamp at time zone ?4, 'yyyy-MM-dd') " +
                "ORDER BY source, to_char(timestamp at time zone ?4, 'yyyy-MM-dd')")
List<Object[]> minMax(long source, Calendar from, Calendar to, String timezone);

With the query in this form, I get 通过这种形式的查询,我得到

event.timestamp must appear in GROUP_BY clause or be used in an aggregate function event.timestamp必须出现在GROUP_BY子句中或在聚合函数中使用

Debugging the Hibernate SQL shows the query as: 调试Hibernate SQL将查询显示为:

DEBUG SQL:109 - SELECT source, to_char(timestamp at time zone ?, 'yyyy-MM-dd') as "date", min(decimalreading), max(decimalreading), avg(decimalreading) FROM reading, event WHERE reading.event = event.id and timestamp at time zone ? 调试SQL:109-选择源,将to_char(时区的时间戳为?,“ yyyy-MM-dd”)作为“日期”,min(十进制读数),max(十进制读数),avg(十进制读数)来自读取,事件在哪里读取。 event = event.id和时间戳在时区? between ? 之间? and ? 和? GROUP BY event.source, to_char(timestamp at time zone ?, 'yyyy-MM-dd') ORDER BY source, to_char(timestamp at time zone ?, 'yyyy-MM-dd') GROUP BY event.source,to_char(时区?的时间戳,“ yyyy-MM-dd”)ORDER BY source,to_char(时区?的时间戳,“ yyyy-MM-dd”)

If I enclose ?4 in single quotes ('?4') I get 如果将?4括在单引号('?4')中,我得到

java.lang.IllegalArgumentException: Parameter with that position [4] did not exist java.lang.IllegalArgumentException:该位置为[4]的参数不存在

so clearly that works no better, and it doesn't see the parameter in the query at all. 如此清楚地表明,这种方法效果更好,并且根本看不到查询中的参数。

I've also tried ''?4'' and \\'?4\\', with no better success. 我也尝试过“?4”和“?4”,但没有取得更好的成功。

If I replace the ?4 positional parameter with a hard-coded value of 'cst5cdt', the query executes successfully. 如果我将“ 4”位置参数替换为“ cst5cdt”的硬编码值,则查询将成功执行。 It also executes nicely via a sql prompt in pgadmin. 它还可以通过pgadmin中的sql提示符很好地执行。

I suspect this is a problem with either the prepared statement, or with the way the positional parameters are being handled. 我怀疑这与准备好的语句或位置参数的处理方式有关。

Is there a syntax that will allow me to aggregate the data for the day, in the time zone passed in as a parameter? 是否有一种语法可以让我在作为参数传入的时区中汇总当天的数据?

I found one way to do this, although it's a bit complicated. 我发现了一种方法,尽管它有些复杂。 Selecting the timezone as a subquery allows it to be interpolated correctly into the main query: 选择时区作为子查询,可以将其正确插入到主查询中:

@Query(nativeQuery=true, value="SELECT source, to_char(timestamp at time zone local.tz, 'yyyy-MM-dd') as \"date\", min(decimalreading), max(decimalreading), avg(decimalreading) " +
                "FROM reading, event, (select ?4 as tz) as local " +
                "WHERE reading.event = event.id "+
                "and source = ?1 " +
                "and timestamp at time zone local.tz between ?2 and ?3 "+
                "GROUP BY event.source, to_char(timestamp at time zone local.tz, 'yyyy-MM-dd') " +
                "ORDER BY well, to_char(timestamp at time zone local.tz, 'yyyy-MM-dd')")
List<Object[]> minMax(long source, Calendar from, Calendar to, String timezone);

Interested to hear if there are other ways that might be less... crufty. 有兴趣了解是否还有其他方法可能会少一些... ft脚。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM