MSSQL Invalid Syntax with Hibernate when using DISTINCT? - java

So I have this piece of Java code:
final Query query = session.createSQLQuery("SELECT DISTINCT(expense_document.id) FROM expense_document JOIN generic_object ON expense_document.id = generic_object.id JOIN expense_document_item ON expense_document_item.document_id = expense_document.id JOIN generic_object ON expense_document_item.id = generic_object.id WHERE expense_document.client_id = :client_id").setParameter("client_id", client.getId()).setMaxResults(1000);
and when this code is executed I get:
org.hibernate.exception.SQLGrammarException: could not execute query
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near the keyword 'from'.
I can not find what MS SQL does not like about this query. When I am connected to MySQL, this line will not cause any problems.

Try removing the parenthesis around the parameter to the distinct keyword.
Use it like this:
select distinct something from somewhere

Your query looks fine.. are you using an up to date driver for MSSQL?
See how to configure hibernate config file for sql server for supported SQL server drivers.
You should be able to do:
final Query query = session.createSQLQuery("SELECT DISTINCT(expense_document.id) FROM expense_document JOIN generic_object ON expense_document.id = generic_object.id JOIN expense_document_item ON expense_document_item.document_id = expense_document.id JOIN generic_object ON expense_document_item.id = generic_object.id WHERE expense_document.client_id = :client_id").setParameter("client_id", client.getId()).setMaxResults(1000);
or
final Query query = session.createSQLQuery("SELECT DISTINCT expense_document.id FROM expense_document JOIN generic_object ON expense_document.id = generic_object.id JOIN expense_document_item ON expense_document_item.document_id = expense_document.id JOIN generic_object ON expense_document_item.id = generic_object.id WHERE expense_document.client_id = :client_id").setParameter("client_id", client.getId()).setMaxResults(1000);
However, if you're using hibernate, why aren't you using HQL, JPA Query language or Criteria? That should ensure that you don't have to change SQL syntax depending upon the vendor as they differ slightly in different flavours. I feel using JPA with entity manager might be the way forward if you're switching between different databases as createSqlQuery will send the string as native SQL to the vendor.
Hibernate EntityManager implements the programming interfaces and
lifecycle rules as defined by the JPA 2.0 specification
https://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html_single/
If you're using something like hibernate, then createSqlQuery is really good for sending vendor specific queries when you want to set hints for example.

Related

Hibernate Query returns duplicate result set when using H2 and HSQL DB

i'm working on a desktop app and i need to use an embedded database however a particular query in hibernate return a duplicated result set when i'm using HSQL or H2 database but it work fine using Mysql
This is the HQL
session.createQuery("SELECT tr FROM Record r INNER JOIN r.trackers tr WHERE r.id = :id AND tr.product = :product");
Your query looks wrong. Perhaps it is not the full query you are running. You need to specify the columns used for joining the two tables. I have added pseudo-code inside < > markers.
SELECT <the columns> FROM Record r INNER JOIN trackers tr
<ON (r.joincolumn = tr.joincolumn)>
WHERE r.id = :id AND tr.product = :product

JPA criteria JOIN: what does {oj ...} mean in SQL?

I learn JPA and tried the following code:
CriteriaBuilder queryBuilder = em.getCriteriaBuilder();
CriteriaQuery<PersonDI> criteriaQuery = queryBuilder.createQuery(PersonDI.class);
Root<PersonDI> personDI = criteriaQuery.from(PersonDI.class);
Fetch<PersonDI, ContactDI> contactDI = personDI.fetch("contacts", JoinType.LEFT);
criteriaQuery.where(queryBuilder.equal(personDI.get("guid"), guids.get(0)));
criteriaQuery.select(personDI).distinct(true);
TypedQuery<PersonDI> query = em.createQuery(criteriaQuery);
So one person has many contacts. The code is working. I use H2 database and EclipseLink. However, I can't understand what {oj...} means in SQL. Explain please.
This is the generated SQL:
SELECT DISTINCT t1.col0, t1.col3, t1.col1, t1.col2, t0.col0, t0.col2 FROM {oj tbl0 t1 LEFT OUTER JOIN tbl1 t0 ON (t0.col1 = t1.col0)} WHERE (t1.col0 = ?)
This is not specific to JPA or SQL, but it is part of the JDBC specification. The JDBC specification contains a number of escapes that are intended to address (potential) incompatibilities between SQL implementations. Drivers are expected to translate this to the database specific SQL.
The {oj <join-definition>} is an escape for an outer join.
To quote from the JDBC 4.2 specification section 13.4.3 Outer Joins:
Outer joins are an advanced feature and are not supported by all data sources. Consult relevant SQL documentation for an explanation of outer joins.
The escape syntax for an outer join is:
{oj <outer-join>}
where <outer-join> has the form:
table {LEFT|RIGHT|FULL} OUTER JOIN {table | <outer-join>} ON search-condition
(Note that curly braces ({}) in the preceding line indicate that one of the items between them must be used; they are not part of the syntax.) The following SELECT statement uses the escape syntax for an outer join.
Statement stmt = con.createStatement();
stmt.executeQuery("SELECT * FROM {oj TABLE1 " +
"LEFT OUTER JOIN TABLE2 ON DEPT_NO = 003420930}");
The JDBC API provides three DatabaseMetaData methods for determining the kinds of outer joins a driver supports: supportsOuterJoins, supportsFullOuterJoins, and supportsLimitedOuterJoins.
Nowadays almost all databases support the SQL standard outer join syntax, so most drivers will simply remove the {oj and } around this. However other JDBC escapes still have their place to address differences between databases.
Interestingly, as a JPA implementation usually knows the specific database in use, I would have expected this to generate database specific SQL instead of using the form with JDBC escapes.

JPA - My Named Query won't work

I am having some problems, with the first time I've gotten into JPA. This is the query I'd like to put in as an #NamedQuery, and this SQL works.
select t1.*, t2.SHORT_NAME from ePluribusWS.GRAPH_ACL t1 join DB_AUTH.USERS t2 on t1.USER_ID = t2.ID where GRAPH_ID = 31611 ;
I'm not sure if this is supported within JPA, since I'm doing a JOIN across different databases, but within the same server. The SQL works fine.
When I try and add this in as a named query (the third one below) I get an error message (Syntax error parsing) that "A path expression cannot end with a comma" which the only Google'ing of shows me JPA source code which generated the error message.
#Entity
#Table(name = "GRAPH_ACL", catalog = "ePluribusWS", schema = "")
#XmlRootElement
#NamedQueries({
.
.
#NamedQuery(name = "EPluribusACLEntryRecord.findByUserId", query = "SELECT g FROM ACLEntryRecord g WHERE g.userId = :userId"),
#NamedQuery(name = "EPluribusACLEntryRecord.findByGraphId", query = "SELECT t1.*, t2.SHORT_NAME FROM ACLEntryRecord t1 JOIN DB_AUTH.USERS t2 ON t1.USER_ID = t2.ID WHERE t1.GRAPH_ID = :graphId"),
#NamedQuery(name = "EPluribusACLEntryRecord.findByCreated", query = "SELECT g FROM ACLEntryRecord g WHERE g.created = :created"),
I'm sort of confused, since it looked like the JPA annotations required that they end with a comma.
Thanks for taking the time to read my question, and provide any insight. Normally, editors remove this "thanks" section, which I think is sort of an unpleasant edit.
A NamedQuery is JPQL, not SQL. There is no "*" and "DB_AUTH.USERS" is an invalid construct in JPQL ... has to refer to entities relative to the candidate entity (the entity defines where its schema is).
If you wanted to refer to tables that are not mapped to entities then you would have to use an SQL query (NamedNativeQuery)

Executing hibernate template's findByNamedQuery

I'm pretty new to hibernate and I was trying it out in one of my applications. I chose to use annotation session factory bean and my editor generated entity classes for each table from the DB which had named queries. hibernateTemplate.findByAll worked fine. But when I tried hibernateTemplate.findByNamedQuery("findById", "<some_id>"), it gave an error: java.lang.IndexOutOfBoundsException: Remember that ordinal parameters are 1-based. After a bit of googling, tried out multiple solutions:
Changed the namedQuery that was generated by editor from : #NamedQuery(name = "Table.findById", query = "SELECT u FROM Table t WHERE t.id = :id"), to : #NamedQuery(name = "Table.findById", query = "SELECT u FROM Table t WHERE t.id = ?") but got the same error.
Tried using hibernateTemplate.findByNamedParam but ended up getting error: java.lang.IllegalArgumentException: node to traverse cannot be null!
I can use hibernateTemplate.find() to achieve this but how do I use findByNamedQuery/Param methods to achieve the same since the documentation says these methods may be used to fetch records based on a field?

Getting error in joining tables using hibernate

I am trying to join multiple table using hibernate but its not working for me can someone please help me out.
I tried Criteria that was not working then thought of using query even that is not working
My code looks like
final Session session = getSession();
String query = "SELECT r.REFERRER_ID from REFERRAL_PAYMENT_INFO r, SIGNUP_REFERRAL s";
Query q = session.createQuery(query);
List list = q.list();
I am getting this error -
"Caused by: org.hibernate.hql.ast.QuerySyntaxException:
REFERRAL_PAYMENT_INFO is not mapped [SELECT r.REFERRER_ID from REFERRAL_PAYMENT_INFO
r, SIGNUP_REFERRAL s]"
You must use the classes (entities) you mapped in HQL queries. If you want to use normal SQL, then you have to call session.createSQLQuery().
Look at the documentation for hibernate session:
http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html

Categories