Blank FROM clause in JPQL? - sql

I'm using a JPQL select to access a Oracle DB function: select FUNCTION('function_name', 'foo', 1234) from com_mycompany_bar obj
This works as expected and the function is indeed called. The thing is I actually don't need the FROM clause and would rather have it empty instead of having to access an entity just to conform to the syntax.
What is the best option I have here?

I see several possible answers:
Within standard JPA there are two options, both involving Oracle DUAL "table"
Map DUAL to an entity and use it in the FROM clause. It is the more "JPQL" way, but it is more involved:
In Java code:
#Entity(name = "Dual")
#Table(name = "SYS.DUAL")
public class Dual {
#Id
#Column(name = "DUMMY")
private String dummy;
}
In orm.xml:
<named-query name="yourQuery">
<query><![CDATA[
SELECT FUNCTION('function_name', 'foo', 1234) FROM Dual d
]]>
</query>
</named-query>
In client code:
Query q = entityManager.createNamedQuery("yourQuery");
Just use a native query that uses DUAL
In orm.xml:
<named-native-query name="yourQuery">
<query><![CDATA[
SELECT function_name('foo', 1234) from sys.dual
]]>
</query>
</named-native-query>
In client code:
Query q = entityManager.createNativeQuery("yourQuery");
As a last option, you can use some JPA implementation extension to JPA and avoid DUAL:
Eclipselink:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/StoredProcedures
http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_namedstoredprocedurequery.htm
http://ronaldoblanc.blogspot.com.br/2012/05/jpa-eclipselink-and-complex-parameters.html
Hibernate:
http://objectopia.com/2009/06/26/calling-stored-procedures-in-jpa/
jpa calling stored procedure with output cursor
How to call Oracle Function or Procedure using Hibernate 4 (EntityManager) or JPA 2

In short: I don't think it's possible to skip FROM clause of JPQL query.
JPQL grammar requires FROM clause to be present (see e.g. here or here).
Calling stored procedures/functions is typically done via native queries (see: createNativeQuery). So this should work:
em.createNativeQuery("select function_name('foo', 1234)").getSingleResult()
UPDATE (from comments):
That's true that JPA native queries don't support named parameters. So you must decide which is the lesser of two evils for you: either using JPQL with unnecessary entity reference or native query with positional parameters instead of named.
But be aware that FUNCTION is EclipseLink extension so it won't work should you decide to change a vendor.

Related

Use unaccent postgres extension in Knex.js Querys

I need make a query for a postgresdb without identify accents (á, í,ö, etc).
I'm already use Knex.js as query builder, and postgresql have a unaccent extension that works fine in sql querys directly to db, but in my code i use knex and unaccent function throws error in querys.
Can anyone help me, ¿is possible make querys with knex.js that use unaccent function of postgresql?
My solution is to process the string before submitting the query using the following code:
const normalize = (str) => str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
console.log(normalize('Ấ Á Ắ Ạ Ê')) -> 'A A A A A'.
Or if you use postgresql version 13 or later it already supports that functionality.
select normalize('hồ, phố, ầ', NFC) → 'ho, pho, a' -- NFC (the default), NFD, NFKC, or NFKD.
Document: https://www.postgresql.org/docs/13/functions-string.html

Using PosgreSQL array_agg with join alias in JOOQ DSL

I want to convert this SQL query to JOOQ DSL.
select "p".*, array_agg("pmu") as projectmemberusers
from "Projects" as "p"
join "ProjectMemberUsers" as "pmu" on "pmu"."projectId" = "p"."id"
group by "p"."id";
Currently i have tried doing something like this using JOOQ:
val p = PROJECTS.`as`("p")
val pmu = PROJECTMEMBERUSERS.`as`("pmu")
val query = db.select(p.asterisk(), DSL.arrayAgg(pmu))
.from(p.join(pmu).on(p.ID.eq(pmu.PROJECTID)))
.groupBy(p.ID)
This does not work because DSL.arrayAgg expects something of type Field<T> as input.
I am new to JOOQ and not an SQL professional. Detailed explanations and impovement suggestions are highly appreciated.
First of all, the syntax indeed works, checked this in SQL Fiddle: http://sqlfiddle.com/#!17/e45b7/3
But it's not documented in detail: https://www.postgresql.org/docs/9.5/static/functions-aggregate.html
https://www.postgresql.org/docs/current/static/rowtypes.html#ROWTYPES-USAGE
That's probably the reason jOOQ doesn't support this currently: https://github.com/jOOQ/jOOQ/blob/master/jOOQ/src/main/java/org/jooq/impl/DSL.java#L16856
The only syntax that will work currently is with a single field: DSL.arrayAgg(pmu.field(1))
What you're looking for is a way to express PostgreSQL's "anonymous" nested records through the jOOQ API, similar to what is requested in this feature request: https://github.com/jOOQ/jOOQ/issues/2360
This is currently not possible in the jOOQ API as of version 3.11, but it definitely will be in the future.
Workaround 1
You could try using the experimental DSL.rowField() methods on a Row[N]<...> representation of your table type. This may or may not work yet, as the feature is currently not supported.
Workaround 2
A workaround is to create a type:
create type my_type as (...) -- Same row type as your table
And a view:
create view x as
select "p".*, array_agg("pmu"::my_type) as projectmemberusers
from "Projects" as "p"
join "ProjectMemberUsers" as "pmu" on "pmu"."projectId" = "p"."id"
group by "p"."id";
And then use the code generator to pick up the resulting type.

How to use a dynamic parameter in a IN clause of a JPA named query?

my problem is about this kind of query :
select * from SOMETABLE where SOMEFIELD in ('STRING1','STRING2');
the previous code works fine within Sql Developer.
The same static query also works fine and returns me a few results;
Query nativeQuery = em.createNativeQuery(thePreviousQuery,new someResultSet());
return nativeQuery.getResultList();
But when I try to parameterize this, I encounter a problem.
final String parameterizedQuery = "select * from SOMETABLE where SOMEFIELD in (?selectedValues)";
Query nativeQuery = em.createNativeQuery(parameterizedQuery ,new someResultSet());
nativeQuery.setParameter("selectedValues","'STRING1','STRING2'");
return nativeQuery.getResultList();
I got no result (but no error in console).
And when I look at the log, I see such a thing :
select * from SOMETABLE where SOMEFIELD in (?)
bind => [STRING1,STRING2]
I also tried to use no quotes (with similar result), or non ordered parameter (:selectedValues), which leads to such an error :
SQL Error: Missing IN or OUT parameter at index:: 1
I enventually tried to had the parentheses set directly in the parameter, instead of the query, but this didn't work either...
I could build my query at runtime, to match the first (working) case, but I'd rather do it the proper way; thus, if anyone has an idea, I'll read them with great interest!
FYI :
JPA version 1.0
Oracle 11G
JPA support the use of a collection as a list literal parameter only in JPQL queries, not in native queries. Some JPA providers support it as a proprietary feature, but it's not part of the JPA specification (see https://stackoverflow.com/a/3145275/1285097).
Named parameters in native queries also aren't part of the JPA specification. Their behavior depends on the persistence provider and/or the JDBC driver.
Hibernate with the JDBC driver for Oracle support both of these features.
List<String> selectedValues = Arrays.asList("STRING1", "STRING2");
final String parameterizedQuery = "select * from SOMETABLE where SOMEFIELD in (:selectedValues)";
return em.createNativeQuery(parameterizedQuery)
.setParameter("selectedValues", selectedValues)
.getResultList();
Instead of:
nativeQuery.setParameter("selectedValues", params);
I had to use:
nativeQuery.setParameterList("selectedValues", params);
This worked for me in derby. parameter without "()".
List<String> selectedValues = Arrays.asList("STRING1", "STRING2");
final String parameterizedQuery = "select * from SOMETABLE where SOMEFIELD in
:selectedValues";
return em.createNativeQuery(parameterizedQuery)
.setParameter("selectedValues", selectedValues)
.getResultList();
Replace this:
nativeQuery.setParameter("selectedValues","'STRING1','STRING2'");
with
List<String> params;
nativeQuery.setParameter("selectedValues",params);
I also faced the same issue.
This is what I did:
List<String> sample = new ArrayList<String>();
sample.add("sample1");
sample.add("sample2");
And now you, can set the sample in params.

Entity Framework Dynamic Lambda to Perform Search

I have the following entities in Entity Framwork 5 (C#):
OrderLine - Id, OrderId, ProductName, Price, Deleted
Order - Id, CustomerId, OrderNo, Date
Customer - Id, CustomerName
On the order search screen the user can enter the following search values:
ProductName, OrderNo, CustomerName
For Example they might enter:
Product Search Field: 'Car van bike'
Order Search Field: '100 101 102'
Customer Search Field: 'Joe Jack James'
This should do a OR search (ideally using linq to entities) for each entered word, this example would output the following where sql.
(ProductName like 'Car' Or ProductName like 'van' Or ProductName like 'bike') AND
(OrderNo like '100' Or OrderNo like '101' Or OrderNo like '102') AND
(CustomerName like 'Joe' Or CustomerName like 'Jack' Or CustomerName like 'James')
I want to do this using linq to entities, i am guessing this would need to be some sort of dynamic lambda builder as we don't know how many words the user might enter into each field.
How would i go about doing this, i have had a quick browse but cant see anything simple.
You can build a lambda expression using Expression Trees . What you need to do is split the value and build the expression . Then you can convert in in to a lambda expression like this,
var lambda = Expression.Lambda<Func<object>>(expression);
Here is an example
There are 2 basic approaches to Dynamic Expressions and Queries in LINQ.
3 if you count using Json as the approach to get a lambda expression. => Akash Kava post
a) String Dynamic Lambda
System.Linq.Dynamic can be found at following links
http://msdn.microsoft.com/en-US/vstudio/bb894665.aspx
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
http://www.scottgu.com/blogposts/dynquery/dynamiclinqcsharp.zip
b) Build Expression trees
More powerful but harder to master...
Build expressions trees with code found here:
http://msdn.microsoft.com/en-us/library/system.linq.expressions.aspx
an alternate approach is predicate builder but it isnt really that dynamic.
but can deal with the OR type scenario you give as example.
http://www.albahari.com/nutshell/predicatebuilder.aspx
I would recomend to go slightly different way from answers above and use EntitySQL as it is trivial to build SQL-like string with dynamic conditions.
http://msdn.microsoft.com/en-us/library/bb738683.aspx
Disclaimer: I am author of Entity REST SDK.
You can look at Entity REST SDK at http://entityrestsdk.codeplex.com
You can query using JSON syntax as shown below,
/app/entity/account/query?query={AccountID:2}&orderBy=AccountName
&fields={AccountID:'',AcccountName:''}
You can use certain extensions provided to convert JSON to lambda.
And here is details of how JSON is translated to Linq. http://entityrestsdk.codeplex.com/wikipage?title=JSON%20Query%20Language&referringTitle=Home
Current Limitations of OData v3
Additionally, this JSON based query is not same as OData, OData does not yet support correct way to search using navigation properties. OData lets you search navigation property inside a selected entity for example Customer(1)/Addresses?filter=..
But here we support both Any and Parent Property Comparison as shown below.
Example, if you want to search for List of Customers who have purchased specific item, following will be query
{ 'Orders:Any': { 'Product.ProductID:==': 2 } }
This gets translated to
Customers.Where( x=> x.Orders.Any( y=> y.Product.ProductID == 2))
There is no way to do this OData as of now.
Advantages of JSON
When you are using any JavaScript frameworks, creating query based on English syntax is little difficult, and composing query is difficult. But following method helps you in composing query easily as shown.
function query(name,phone,email){
var q = {};
if(name){
q["Name:StartsWith"] = name;
}
if(phone){
q["Phone:=="] = phone;
}
if(email){
q["Email:=="] = email;
}
return JSON.stringify(q);
}
Above method will compose query and "AND" everything if specified. Creating composable query is great advantage with JSON based query syntax.

From within a grails HQL, how would I use a (non-aggregate) Oracle function?

If I were retrieving the data I wanted from a plain sql query, the following would suffice:
select * from stvterm where stvterm_code > TT_STUDENT.STU_GENERAL.F_Get_Current_term()
I have a grails domain set up correctly for this table, and I can run the following code successfully:
def a = SaturnStvterm.findAll("from SaturnStvterm as s where id > 201797") as JSON
a.render(response)
return false
In other words, I can hardcode in the results from the Oracle function and have the HQL run correctly, but it chokes any way that I can figure to try it with the function. I have read through some of the documentation on Hibernate about using procs and functions, but I'm having trouble making much sense of it. Can anyone give me a hint as to the proper way to handle this?
Also, since I think it is probably relevant, there aren't any synonyms in place that would allow the function to be called without qualifying it as schema.package.function(). I'm sure that'll make things more difficult. This is all for Grails 1.3.7, though I could use a later version if needed.
To call a function in HQL, the SQL dialect must be aware of it. You can add your function at runtime in BootStrap.groovy like this:
import org.hibernate.dialect.function.SQLFunctionTemplate
import org.hibernate.Hibernate
def dialect = applicationContext.sessionFactory.dialect
def getCurrentTerm = new SQLFunctionTemplate(Hibernate.INTEGER, "TT_STUDENT.STU_GENERAL.F_Get_Current_term()")
dialect.registerFunction('F_Get_Current_term', getCurrentTerm)
Once registered, you should be able to call the function in your queries:
def a = SaturnStvterm.findAll("from SaturnStvterm as s where id > TT_STUDENT.STU_GENERAL.F_Get_Current_term()")