JPQL / JPA query to order entities based on the greatest/maximum of two columns? - jpa

I need something similar to this SQL query:
SELECT * FROM foo f ORDER BY GREATEST(f.bar_date, f.baz_date)
As not all RDBMS systems support the GREATEST function, ideally I would like the JPA implementation to generate the correct SQL query for the underlying database. The databases that I am targetting are Oracle, SQL Server, and PostgreSQL.

JPQL allows the FUNCTION operator to call a database function.
Oracle and Postgres support GREATEST, I don't think SQL Server does, so for it you may be able to write your own function.
You could also use a CASE function with >.

To put this a little more concrete - you could do this in JPQL with the CASE statement, which is supported since JPA 2.0. I've omitted the _date suffixes for brevity.
SELECT * FROM foo f ORDER BY CASE WHEN f.bar > f.baz THEN f.bar ELSE f.baz END

I've used CASE function.
Via criteria builder it looks like:
CriteriaQuery<?> query = ...
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
query.orderBy(builder.selectCase().when(builder.greaterThan(pathToBarDate, pathToBazDate),pathToBarDate).otherwise(pathToBazDate));
In JPQL it should look like
ORDER BY
CASE WHEN (f.bar_date>f.baz_date) THEN f.bar_date
ELSE f.baz_date

Related

What if PostgreSql introduce a new function with name "cypher" then how to distingush between cypher and sql query with cypher function

Currently, the structure of Apache-age query is:
SELECT * FROM cypher(<graph_name>, <cypher_query>)
I am not sure how PostgreSQL is able to distinguish between regular sql queries and Cypher queries after loading age extension.
For now parsers can differentiate between cypher query and normal SQL queries by looking at cypher function in the from clause of select statement. [We are using this approach to distinguish between cypher and normal queries]
But I was concerned that if PostgreSql introduce a new function with the name "cypher" for some functionality, let's say that cypher function can be used in from-clause like we use generate_series in from-clause in the following example.
SELECT * FROM generate_series(1, 10) AS number;
Then there will be conflict in between. How can we resolve that in development?
If PostgreSQL introduces a new system function, that function will be in the system schema pg_catalog. You can disambiguate between such a function and your function by qualifying the function name with the schema, for example
SELECT myschema.cypher(...);

CosmosQueryableExtensions.FromSqlRaw generates undesired sub query

I have a scenario where I need to create raw query towards CosmosDb. For the sake of this question, I have a simplified call:
CosmosQueryableExtensions.FromSqlRaw(db.ProjectFolders, "SELECT VALUE c FROM c WHERE c.Site = \"mysite\"")
but it generates query with undesired subquery:
info: Microsoft.EntityFrameworkCore.Database.Command[30102]
Executed ReadNext (784.3342 ms, 2.85 RU) ActivityId='3f8b0dfd-09f5-4fd3-99e3-3bae8edbe06e', Container='Items', Partition='?', Parameters=[]
SELECT c
FROM (
SELECT VALUE c FROM c WHERE c.Site = "mysite"
) c
Is this by design, irrelevant, or am I doing something wrong?
Explaination :- FromSQLRow generates query with in subquery and its by design.
Composing query with LINQ, EF Core will consider passed LINQ SQL query as subquery over the database. Composing SQL query with in LINQ starts with SELECT but can't have SQL like features such as
Trailing semicolon (;)
ORDER BY clause
References :-
https://learn.microsoft.com/en-us/ef/core/querying/sql-queries#composing-with-linq
Include with FromSqlRaw and stored procedure in EF Core 3.1
How do I access the VALUE using CosmosQueryableExtensions

Is there such a thing as a "PostgreSQL-SQL-to-OtherDB-SQL" converter in PHP, or at all?

I use PostgreSQL exclusively. I have no plans to ever change this. However, I recognize that other people are not me, and they instead use MySQL, MS SQL, IBM SQL, SQLite SQL, Oracle SQL and ManyOthers SQL. I'm aware that they have different names in reality.
My queries look like:
SELECT * FROM table WHERE id = $1;
UPDATE table SET col = $1 WHERE col = $2;
INSERT INTO table (a, b, c) VALUES ($1, $2, $3);
My database wrapper functions currently support only PostgreSQL, by internally calling the pg_* functions.
I wish to support "the other databases" too. This would involve (the trivial part) to make my wrapper functions able to interact with the other databases by using the PHP functions for those.
The difficult part is to reconstruct the PostgreSQL-flavor SQL queries from the application into something that works identically yet will be understood by the other SQL database in use, such as MySQL. This obviously involves highly advanced parsing, analysis and final creation of the final query string. For example, this PostgreSQL SQL query:
SELECT * FROM table WHERE col ILIKE $1 ORDER BY random() LIMIT 1;
... will be turned into WeirdSQL like this:
SELECT * FROM table WHERE col ISEQUALTOKINDA %1 ORDER BY rnd() LIMIT 1;
I don't require support from any other input SQL flavor than PostgreSQL, but the output must be "all the big SQL database vendors".
Has anyone even attempted this? Or is it something that is never gonna happen as free software but might exist as a commercial offering? It sounds like it would be a thing. It would be insanely useful, and "crazier" projects have been attempted.
jOOQ is a Java library that aims to hide differences between databases. It has its own SQL grammar which tries to be compatible with everything (but parameter markers must be the JDBC ?), and generates DB-specific SQL from that.
There is an online translator, which generates the following from your query for Oracle:
select *
from table
where lower(cast(col as varchar2(4000))) like lower(cast(:1 as varchar2(4000)))
order by DBMS_RANDOM.RANDOM
fetch next 1 rows only
ODBC uses its own syntax on top on the database's syntax. ODBC drivers are required to convert ODBC parameter markers (?) to whatever the database uses, and to translate escape sequences for certain elements that are likely to have a non-standard syntax in the DB (time/GUID/interval literals, LIKE escape character, outer joins, procedure calls, function calls).
However, most escape sequences are optional, and this does not help with other syntax differences, such as the LIMIT 1.
ODBC drivers provide a long list of information about SQL syntax details, but it is the application's job to construct queries that conform to those restrictions, and not all differences can be described by this list. In practice, most ODBC applications restrict themselves to a commonly supported subset of SQL.

Table Valued Functions in EF Core

I am using EF Core 1.1 and have a query like
var list=from l in context.Users
where l.SomeProp==someVal
select l;
I have a UDF which returns a table of Id's and I basically want to generate the following query:
select * from Users where SomeProp=#someVal and SomeId in (select id from fn_myfunc(#id))
Is this possible to do?
I think you are limited to running a raw SQL query against the database to be able to use a table valued function. For example:
var query = #"SELECT * FROM Users WHERE SomeProp = {0}
AND SomeId IN (SELECT id FROM fn_myfunc({1})";
var users = context.Users
.FromSql(query, someProp, someId)
.ToList();
There are some limitations with this method. From the docs:
SQL queries can only be used to return entity types that are part of your model. There is an enhancement on our backlog to enable returning ad-hoc types from raw SQL queries.
The SQL query must return data for all properties of the entity type.
The column names in the result set must match the column names that properties are mapped to. Note this is different from EF6.x where property/column mapping was ignored for raw SQL queries and result set column names had to match the property names.
The SQL query cannot contain related data. However, in many cases you can compose on top of the query using the Include operator to return related data.
You can return related data (i.e. Include) like this:
var users = context.Users
.FromSql(query, someProp, someId)
.Include(u => u.OtherThings)
.ToList();
If you need to do anything more complex, then you would need to either drop down to using raw data access (like ADO.Net) or another ORM. I know people who use EF Core for the bulk of the work and then occasionally drop into Dapper for performance or raw SQL that doesn't suit EF.

OpenJpa how to find length of string in JPQL

I am using
length(ze.string)>2 in openJpa query. but i am getting
SQLCODE=-440, SQLSTATE=42884, SQLERRMC=CHAR_LENGTH;FUNCTION, DRIVER=3.53.95 {prepstmnt 1776269692 SELECT t0.f1, t0.f2, t0.f3, t0.f4, t0.f5, t0.f6, t0.f7, t0.f8, t0.f9, t0.f10, t0.f11, t0.f12, t0.f13, t0.f14, t0.f15, t0.f16, t0.f17 FROM table t0 WHERE (t0.f1 = ? AND CHAR_LENGTH(?) > ? AND .....
In plain query when i do length operation i am getting record but using jpa its not working. I looked Here used size it doesn't work. and the field is varchar and db2. trying from past 1 hour.
DB2 requires use of the SQL function LENGTH, yet OpenJPA seems to be incorrectly converting your JPQL to use SQL function CHAR_LENGTH (hence the error message - not that DB2 gives out clear messages saying what is wrong, who knows what SQLCODE=-440 is without having to search!!).
Raise a bug on your JPA provider.
See https://www.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000818.html
You would need to give more details about your entity, persistence.xml, and query to get to the bottom or this. However, I do not see how OpenJPA would use CHAR_LENGTH instead of LENGTH for DB2. Let me explain. If you look at DBDictionary here:
https://svn.apache.org/viewvc/openjpa/branches/2.2.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?view=markup
You can see it defines something called "stringLengthFunction" as follows:
public String stringLengthFunction = "CHAR_LENGTH({0})";
This is the string length function which should be used for each individual dictionary (i.e. Database config). However, for DB2, the AbstractDB2Dictionary, see here:
https://svn.apache.org/viewvc/openjpa/branches/2.2.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java?view=markup
overrides this as follows:
stringLengthFunction = "LENGTH({0})";
Given this, for DB2, LENGTH should be used. I took the following simple query:
"select me.id from MyEntity me where length(me.name)>2"
And executed it on OpenJPA using DB2, and I got this:
SELECT t0.ID FROM MYENTITY t0 WHERE (CAST(LENGTH(t0.ID) AS BIGINT) > CAST(? AS BIGINT)) [params=(long) 2]
Thanks,
Heath Thomann