I am using a query builder to create a query statement in hibernate. i need to pass a arrayList for in statement. How can this be done.
Dummy code :
List<String> xyz = new ArrayList<String>("sam","tam","vam");
StringBuilder queryBuilder = new StringBuilder("select abc from tem where xyz in :xyzList");
Query query = entityManager.createNativeQuery(queryBuilder.toString());
query.setParameter("xyzList", xyz);
query.getResultList();
this is not working. it throws exceptions. Can somebody point me how to do this.
Use setParameterList("xyzList", new String []{"a","b","c"});
So if you have the list with you, you can do list.toArray() in place of new String []{"a","b","c"}
You have seemed to be mistaken an entityManager.createNativeQuery with entityManager.createNamedQuery or entityManager.createQuery
The syntax of your query is JPQL, but you compile it as a native query syntax
What should work for you is to move from createNativeQuery simply to createQuery, or align it the other way around so write a proper native query if that is your goal.
Note just that if you're intent was to go for a native query you should stay away from the named parameters. In your case it would work since you're using hibernate as persistence provider, but otherwise, named parameters in native queries are not supported according to JPA specification
Related
I want to build a cosmosdb sql query, because I'm using a rest interface, which accepts SQL querys (don't ask why, I can't change that :( )...
Now I want to build that query with some parameters, which affects the WHERE clause.
I think it is a good idea to escape these parameters, to prevent sql injection.
But I just found these way to build a query:
var param = new SqlParameter();
param.add("#test", "here some string to inject");
var query = new SqlQuerySpec("SELECT #test FROM table", param);
Now I could do sql calls to the cosmos's without sql injection. But I don't want this. I just want to get the query string.
But I need the full query from "query". But there seems to be just the method query.getQueryText(). But this just returns the string "SELECT #test FROM table".
Do know a workaround for me? Or maybe just a good package I can use to to my own string escapes.
T
I found the information that this escalation stuff doesn't happen on client site. It happens in the dbms. So I need a rest interface, where I can pass the parameters.
Azure Cosmos DB SQL Like, prepared statements
I have problems with understanding of way couchbase query plan works.
I use SpringData with Couchbase 4.1 and I provide custom implementation of Couchbase Repository. Inside my custom implememtnation of Couchbase Repository I have below method:
String queryAsString = "SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS FROM MyDatabase WHERE segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1";
JsonObject params = JsonObject.create()
.put(CLASS_VARIABLE, MyClass.class.getCanonicalName())
.put(ID_VARIABLE, segmentId);
N1qlQuery query = N1qlQuery.parameterized(queryAsString, params);
List<MyClass> resultList = couchbaseTemplate.findByN1QL(query, SegmentMembers.class);
return resultList.isEmpty() ? null : resultList.get(0);
In a result, Spring Data produces following json object represented query to Couchbase:
{
"$class":"path/MyClass",
"statement":"SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS from MyDatabase where segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1",
"id":"6592c16a-c8ae-4a74-bc17-7e18bf73b3f8"
}
And the problem is with performance when I execute it via Java and N1QL Rest Api or via cbq consol. For execute this query in cbq I simply replace parameters reference with exact values.
After adding EXPLAIN clause before select statement I mentioned different execution plans. Execution this query as parameterized query via Java Spring Data or N1QL Rest Api I've mentioned that query doesn't use index that I created exactly for this case. Index definiton can be found below:
CREATE INDEX `testMembers` ON MyDatabase `m`(`_class`,`segmentId`,`executionTime`) WHERE (`_class` = "path/MyClass") USING GSI;
So, when I execute query via cbq consol, Couchbase uses my idnex and query performance is very good. But, when I execute this query via N1QL rest api or Java i see that query doesn't use my index. Below you can find part of execution plan that proves this fact:
"~children": [
{
"#operator": "PrimaryScan",
"index": "#primary",
"keyspace": "CSM",
"namespace": "default",
"using": "gsi"
},
So, the question is that the right and legal behavior of couchbase query optimizer? And does it mean that query plan does not take into account real values of parameters? And have I manually put values into query string or exist eny other way to use N1Ql parameterized query with correct index selection?
EDIT
According to shashi raj answer I add N1qlParams.build().adhoc(false) parameter to parameterized N1QL query. This doesn't solve my problem, because I still have performance problem with this query. Moreover, when I print query I see that it is the same as I described earlier. So, my query still wrong analyzed and cause performance decline.
first of all you need to know how N1QL parameterized queries works query should be passed as:
String query= select * from bucketName where _class=$_class and segmentId=$segmentId LIMIT $limit ;
Now the query should be passed as:
N1QL.parameterized(query,jsonObject,N1qlParams.build().adhoc(false));
where jsonObject will have all the placeholder values.
JsonObject jsonObject=JsonObject.create().put("_class","com.entity,user").put("segmentId","12345").put("limit",100);
N1qlParams.build().adhoc(false) is optional since if you want your query to be optimized it will make use of it. It makes use of LRU where it keeps track of previously query entered and it keeps record of it so that next time it doesn't need to parse query and fetch it from previous what we call as prepared statement.
The only problem is couchbase only keeps record of last 5000 queried.
The problem in your case is caused by the fact that you have an index with 'where' clause WHERE ( _class = "path/MyClass"), and at the same time, you passing the _class as a parameter in your query.
Thus, the query optimizer analyzing the parametrized query has no idea that this query might use an index created for _class = "path/MyClass", cause it's _class = $class in a select's where. Pretty simple, right?
So, don't pass any fields mentioned in your index's 'where' as select parameters. Instead, hardcode _class = "path/MyClass" in your select in the same way you did for create index. And everything should be fine.
Here's the ticket in the couchbase issue tracking system about that.
https://issues.couchbase.com/browse/MB-22185?jql=text%20~%20%22parameters%20does%20not%20use%20index%22
I am writing a query to find dates and their counts for that particular date from my entity table, and running into an issue with the groupBy statement.
Here is my criteria API calls:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
Root<HtEntity> from = criteriaQuery.from(entityClassType);
Expression<String> log_date = criteriaBuilder.function("TO_CHAR",
String.class, from.get(Constants.PARAM_DATE), criteriaBuilder.literal("yyyy-MM-dd")
);
//create the select statement
criteriaQuery.select(
criteriaBuilder.tuple(
log_date.alias("log_date"),
criteriaBuilder.count(from)));
criteriaQuery.groupBy(log_date); //ISSUE HERE!!!
TypedQuery<Tuple> query = em.createQuery(criteriaQuery);
List<Tuple> results = query.getResultList();
Without trying to cast the date column with to_char and using just the date column it works, but obviously is not aggregated as I want to. I want just the date in yyyy-MM-dd and not the entire timestamp, and I can only see doing this by using groupBy which causes an error
"org.hibernate.exception.SQLGrammarException: could not extract
ResultSet"
And there is the query string that is build found from my debugger:
select function('TO_CHAR', generatedAlias0.date, :param0), count(generatedAlias0) from LogMessageEntity as generatedAlias0 group by function('TO_CHAR', generatedAlias0.date, :param1)
Please let me know what I am doing wrong. The corresponding Postgres SQL query should be working for this, as I can test it and see that it would work.
CriteriaApi has a good way of providing me with a headache, but I did end up finding a solution to this a while back, providing the answer for future curious folks:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class);
Root<MyEntity> from = criteriaQuery.from(classType);
criteriaQuery.multiselect(
from.get("date").as(java.sql.Date.class),
criteriaBuilder.count(from)
);
/*Add order by and group by clause*/
criteriaQuery.orderBy(criteriaBuilder.desc(from.get("date").as(java.sql.Date.class)));
criteriaQuery.groupBy(from.get("date").as(java.sql.Date.class));
TypedQuery<Object[]> query = em.createQuery(criteriaQuery);
List<Object[]> results = query.getResultList();
You will notice that I am casting the column projecting in my multi-select statement, and my groupBy as a java.sql.Date type. CriteriaApi has a strict type-safe format such that you cannot mix types for the groupBy and the select statement if you are aggregating on that specific column. My issue was that I was selecting on the date column with a function call, and also trying to apply that to the groupBy.
While the generated query statement works via command line, it does not work for the CriteriaApi. The reason it cannot generate a ResultSet is due to it assuming the projection and aggregation in the groupBy are not the same type (I think) and therefore, if you need to use a function on a column in your select statement and also aggregate on that column you need to either think of a way you can avoid using the function (which is what I did), or generate a native query with the Hibernate EntityManager object you have.
It is unfortunate, but I believe CriteriaApi has a number of limitations with this being one of them. It should probably be submit to their team as a bug, but I'm not sure where to do this.
Old question, but the issue is still relevant. I've tried your solution, but it didn't work for me. What did work is the trunc function, instead of the to_char:
Path<FeedbackType> feedbackTypePath = itemRoot.get("feedbackType");
final Expression date = criteriaBuilder.function("trunc", java.sql.Date.class, votesJoin.get("creationDate"));
selects.add(feedbackTypePath);
selects.add(date);
selects.add(criteriaBuilder.count(itemRoot.get("id")));
criteriaQuery.multiselect(selects);
criteriaQuery.where(criteriaBuilder.equal(votesJoin.get("creationDate"), oldestVoteSubquery));
criteriaQuery.groupBy(feedbackTypePath, date);
It looks like the criteriabuilder does not like the literal in the groupBy.
I need to use the LIKE operator into an JPA query. I need to use it for types other then String but the JPA criteria API allows me to add only String parameters. I tried using the .as(String.class) but something fails and also tried calling the CAST function from the underlying Oracle that again fails for unknown reasons to me.
I tried writing the query also in JPQL and it works as expected. This is the query:
SELECT p from CustomerOrder p where p.id like '%62%'
UPDATE:
The query must be built in a generic fashion as it is for filtering, so it needs to be created at runtime. On the query that is already created I tried to add the LIKE clause like this:
query.where(builder.like(selectAttributePath.as(String.class), "%"+filterValue.toString().toLowerCase()+"%"));
But this crashes with this exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE, found '(' near line 1, column 156 [select distinct generatedAlias0.id from de.brueckner.mms.proddetailschedact.data.CustomerOrder as generatedAlias0 where cast(generatedAlias0.id as varchar2(255 char)) like :param0]
I executed the same query directly to Oracle using SQLDeveloper, so it should be sound from this point of view. So the problem is the Hibernate is the issue. Any suggestions on how to fix it?
How can I write this query using JPA Criteria?
I fixed the problem by invoking the 'TO_CHAR' function from the underlying Oracle DB and using the LIKE operator like for normal String's.
query.where(builder.like(selectAttributePath.as(String.class), "%" +filterValue.toString().toLowerCase() + "%")
You can try the below code, it might require modifications.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CustomerOrder> cq = cb.createQuery(CustomerOrder.class);
Root<CustomerOrder> order = cq.from(CustomerOrder.class);
cq.where(cb.like(Long.valueOf(order.get(CustomerOrder_.id)).toString(), "%62%"));
TypedQuery<CustomerOrder> q = em.createQuery(cq);
List<CustomerOrder> results = q.getResultList();
I want to query my data from A and order-by a field from B, The field in B could be null. Any suggestions? Thanks.
As of version 4.22, ORMLite now supports simple JOIN query syntax. Here is the documentation for it:
http://ormlite.com/docs/join-queries
So your query might be something like:
QueryBuilder<B, Integer> bQb = bDao.queryBuilder();
bQb.orderBy("someBField", true);
QueryBuilder<A, Integer> aQb = aDao.queryBuilder();
List<A> results = aQb.join(bQb).query();
You can also certainly use the dao.queryRaw() methods to construct you own query. Here a good example how you would formulate the query:
SQL order by a column from another table