aggregate function as tuple argument postgres - postgresql

I want to pass aggregate function like min, max etc as query parameter using Tuple.
Below is my query:
"select $5(CAST (vol AS FLOAT)) AS agg_v, "
+ "time_bucket_gapfill" + "(($1::text || ' minutes')::interval, t) AS time_function_minute, "
+ "tag_id from rtdata "
+ "where tag_id = any($2) and t > $3 and t < $4 "
+ "GROUP BY (tag_id, time_function_minute) ORDER BY time_function_minute"
But I'm getting following exception:
io.vertx.pgclient.PgException: syntax error at or near
"("
at io.vertx.pgclient.impl.codec.ErrorResponse.toException(ErrorResponse.java:29)
at io.vertx.pgclient.impl.codec.PrepareStatementCommandCodec.handleErrorResponse(PrepareStatementCommandCodec.java:62)
at io.vertx.pgclient.impl.codec.PgDecoder.decodeError(PgDecoder.java:233)
at io.vertx.pgclient.impl.codec.PgDecoder.decodeMessage(PgDecoder.java:122)
at io.vertx.pgclient.impl.codec.PgDecoder.channelRead(PgDecoder.java:102)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514)
at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:745)
But If I replace $5 with hardcode aggregate function it works. How can I pass aggregate function dynamically in this scenario?
RxJava code Snippet:
return txBegin()
.flatMapObservable(tx ->
tx.rxPrepare(abovesql)
.flatMapObservable(pq -> {
return pq.createStream(50,
Tuple.of(
evalBucketInterval(req),
req.getTags().toArray(new Integer[0]),
parse(req.getStartDate()),
parse(req.getEndDate()),
parse(req.getAggFunc())))
.toObservable();
})
.doAfterTerminate(tx::commit))
.map(this::toFuncJson);

PostgreSQL allows to use parameters only as values and doesn't understand when you try to use parameters for function names, table names, etc. So you cannot pass aggregate name as a parameter.
I suggest to work around it in your application by concatenating the string value containing the aggregate function name. I guess it can be something like, but I am not sure about the exact syntax and what limitations of your environment are:
"select "+ my_agg_func_name +"(CAST (vol AS FLOAT)) AS agg_v, "
+ "time_bucket_gapfill" + "(($1::text || ' minutes')::interval, t) AS time_function_minute, "
+ "tag_id from rtdata "
+ "where tag_id = any($2) and t > $3 and t < $4 "
+ "GROUP BY (tag_id, time_function_minute) ORDER BY time_function_minute"

Related

JPQL: How to rewrite postgres native query to JPQL query that uses filter keyword

Im trying to avoid using native query. I have this query that uses the filter function, how could I rewrite this to not use that and work in regular jpql?
#Query(
"SELECT time_bucket(make_interval(:intervalType), d.time) as groupedDate, " +
"CAST(d.team_Id as varchar) as teamId, CAST(d.service_Id as varchar) as serviceId, CAST(d.work_id as varchar) as workId, " +
"ROUND(CAST(count(d.value) filter ( where d.type = 'A') AS numeric) /" +
" (CAST(count(d.value) filter ( where d.type = 'B') AS numeric)), 4) as total " +
"FROM datapoint d " +
"WHERE d.team_Id = :teamId and d.service_id in :serviceIds and d.work_id = :workspaceId and d.type in ('A', 'B') " +
"AND d.time > :startDate " +
"GROUP BY groupedDate, d.team_Id, d.service_Id, d.workspace_Id " +
"ORDER BY groupedDate DESC",
nativeQuery = true
)
in the FROM statement you have to use the DAO object instead of the table name

An identification variable must be provided for a range variable declaration

I'm trying to use this query in my jpa but it doesn't work:
List<Object[]> query = em.createQuery("SELECT Tstat.idStatistiques, TL.codeLieu, TL.materiel, TL.zone, sum(Tstat.colis) as colis, Tstat.defaut, sum(Tstat.nbreDefaut) as nbreDefaut,"
+ " sum(Tstat.nonLu) as nonLu, sum(Tstat.multiple) as multiple, sum(Tstat.nonRecu) as nonRecu, sum(Tstat.incoherent) as incoherent, sum(Tstat.requete) as requete , "
+ "sum(Tstat.tempsFonctionnement) as tempsFonctionnement, SUM(Tstat.tempsUtilisation) as tempsUtilisation, Tstat.modeFonctionnement FROM "
+ "( SELECT CURRENT_DATE as horodatage, St.idStatistiques, St.colis, St.defaut, St.nbreDefaut, St.nonLu, St.requete, St.multiple, St.nonRecu, St.incoherent, St.tempsFonctionnement, St.tempsUtilisation, St.modeFonctionnement FROM Statistique St )"
+ " UNION "
+ "(SELECT h.horodatage, h.idStatistiques, h.colis, h.defaut, h.nbreDefaut, h.nonLu, h.nonRecu, h.requete, h.multiple, h.incoherent, h.tempsFonctionnement, h.tempsUtilisation, h.modeFonctionnement FROM Statistiqueshisto h )"
+ " Tstat "
+ "LEFT JOIN (SELECT * FROM Lieux) as TL on Tstat.idStatistiques = TL.code_VI WHERE idStatistiques like :A ").setParameter("A", 0040+"%").getResultList();
This gives me error
The expression is invalid, which means it does not follow the JPQL
grammar.

JPQL "DISTINCT" returns only one result

I am confused by DISTINCT in JPQL. I have two JPQL queries identical except for "DISTINCT" in one of them:
String getObjectsForFlow =
"SELECT " +
" se.componentID " +
"FROM " +
" StatisticsEvent se " +
"WHERE " +
" se.serverID IS NOT NULL " +
" AND se.flowID = :uuid " +
" AND se.componentID IS NOT NULL " +
"ORDER BY " +
" se.timeStamp desc ";
String getObjectsForFlowDistinct =
"SELECT DISTINCT " +
" se.componentID " +
"FROM " +
" StatisticsEvent se " +
"WHERE " +
" se.serverID IS NOT NULL " +
" AND se.flowID = :uuid " +
" AND se.componentID IS NOT NULL " +
"ORDER BY " +
" se.timeStamp desc ";
I run a little code to get the results from each query and dump them to stdout, and I get many rows with some duplicates for non-distinct, but for distinct I get only one row which is part of the non-distinct list.
NOT DISTINCT
::: 01e2e915-35c1-6cf0-9d0e-14109fdb7235
::: 01e2e915-35c1-6cf0-9d0e-14109fdb7235
::: 01e2e915-35d9-afe0-9d0e-14109fdb7235
::: 01e2e915-35d9-afe0-9d0e-14109fdb7235
::: 01e2e915-35bd-c370-9d0e-14109fdb7235
::: 01e2e915-35bd-c370-9d0e-14109fdb7235
::: 01e2e915-35aa-1460-9d0e-14109fdb7235
::: 01e2e915-35d1-2460-9d0e-14109fdb7235
::: 01e2e915-35e1-7810-9d0e-14109fdb7235
::: 01e2e915-35e1-7810-9d0e-14109fdb7235
::: 01e2e915-35d0-12f0-9d0e-14109fdb7235
::: 01e2e915-35b0-cb20-9d0e-14109fdb7235
::: 01e2e915-35a8-66b0-9d0e-14109fdb7235
::: 01e2e915-35a8-66b0-9d0e-14109fdb7235
::: 01e2e915-35e2-6270-9d0e-14109fdb7235
::: 01e2e915-357f-33d0-9d0e-14109fdb7235
DISTINCT
::: 01e2e915-35e2-6270-9d0e-14109fdb7235
Where are the other entries? I would expect a DISTINCT list containing eleven (I think) entries.
Double check equals() method on your StatisticsEvent entity class. Maybe those semantically different values returns same when equals() is called hence producing this behavior
The problem was the "ORDER BY se.timeStamp" clause. To fulfill the request, JPQL added the ORDER BY field to the SELECT DISTINCT clause.
This is like a border case in the interplay between JPQL and SQL. The JPQL syntax clearly applies the DISTINCT modifier only to se.componentID, but when translated into SQL the ORDER BY field gets inserted.
I am surprised that the ORDER BY field had to be selected at all. Some databases can return a data set ORDERed by a field not in the SELECTion. Oracle can do so. My underlying database is Derby -- could this be a limitation in Derby?
Oracle does not support SELECT DISTINCT with an order by unless the order by columns are in the SELECT. Not sure if any databases do. It will work in Oracle if the DISTINCT is not required (does not run because rows are unique), but if it needs to run you will get an error.
You will get, "ORA-01791: not a SELECTed expression"
If you are using EclipseLink this functionality is controlled by the DatabasPlatform method,
shouldSelectDistinctIncludeOrderBy()
You can extend your platform to return false if your database does not require this.
Still, I don't see how adding the TIMESTAMP will change the query results?
Both queries are incorrect JPQL queries, because ORDER BY clause refers to the item that is not on select list. JPA 2.0 specification contains example that matches to this case:
The following two queries are not legal because the orderby_item is
not reflected in the SELECT clause of the query.
SELECT p.product_name
FROM Order o JOIN o.lineItems l JOIN l.product p JOIN o.customer c
WHERE c.lastname = ‘Smith’ AND c.firstname = ‘John’
ORDER BY p.price
SELECT p.product_name
FROM Order o, IN(o.lineItems) l JOIN o.customer c
WHERE c.lastname = ‘Smith’ AND c.firstname = ‘John’
ORDER BY
o.quantity
Of course it would be nicer if if implementation could give clear error message instead of trying to guess what is expected result of incorrect query.

Uniquename function in mdx script

I really need your help.
For a SSRS report, I have this mdx script:
select
{[Geographie].[Commune].[AHUY], [Geographie].[Commune].[BRETENIERE]} on columns
,{[Activite].[Branche].&[B], [Activite].[Branche].&[C]} on rows
from [ACSEL2]
where ([Measures].[CATTC], [Perimetre].[Perimetre].&[2], [Temps].[Annee].&[2006])
Please, I need to have the uniquename for the members that I have in columns
({[Geographie].[Commune].[AHUY], [Geographie].[Commune].[BRETENIERE]})
Please Can U help me to write this mdx script ?
Lidou
Declare a member using With statement, like this:
WITH MEMBER [Measures].[UniqueName] as [Geographie].[Commune].CurrentMember.UniqueName
Select
--Your select here
More details on CurrentMember
WITH
-- Geography metadata
MEMBER [Measures].[Geographie]
AS StrToValue ( #SelectionGeographie + ".Hierarchy.Currentmember.Uniquename" )
MEMBER [Measures].[Geographie_Label]
AS StrToValue( #SelectionGeographie + ".Hierarchy.CurrentMember.Member_Caption" )
SELECT NON EMPTY {
[Measures].[Geographie],
[Measures].[Geographie_Label],
[Measures].[11 VA]
} ON COLUMNS,
( STRTOSET ( "{" + #SelectionGeographie + "}") ,
STRTOSET ("{" + #SelectionActivite + "}" ))
ON ROWS
FROM [MyCube]
WHERE STRTOTUPLE ( "(" +#Annee + "," + #Perimetre + ")" )

scala newbie having troubles with Option, what's the equivalent of the ternary operator

I've already read that the if statement in scala always returns an expression
So I'm trying to do the following (pseudo code)
sql = "select * from xx" + iif(order.isDefined, "order by " order.get, "")
I'm trying with
val sql: String = "select * from xx" + if (order.isDefined) {" order by " + order.get} else {""}
But I get this error:
illegal start of simple expression
order is an Option[String]
I just want to have an optional parameter to a method, and if that parameter (in this case order) is not passed then just skip it
what would be the most idiomatic way to achieve what I'm trying to do?
-- edit --
I guess I hurried up too much to ask
I found this way,
val orderBy = order.map( " order by " + _ ).getOrElse("")
Is this the right way to do it?
I thought map was meant for other purposes...
First of all you are not using Option[T] idiomatically, try this:
"select * from xx" + order.map(" order by " + _).getOrElse("")
or with different syntax:
"select * from xx" + (order map {" order by " + _} getOrElse "")
Which is roughly equivalent to:
"select * from xx" + order match {
case Some(o) => " order by " + o
case None => ""
}
Have a look at scala.Option Cheat Sheet. But if you really want to go the ugly way of ifs (missing parentheses around if):
"select * from xx" + (if(order.isDefined) {" order by " + order.get} else {""})
...or, if you really want to impress your friends:
order.foldLeft ("") ((_,b)=>"order by " + b)
(I would still recommend Tomasz's answer, but I think this one is not included in the scala.Option cheat sheet, so i thought I'd mention it)