Parse SQL to sql builder - java

Is there easy way to convert SQL string like:
SELECT u.name, u.role
FROM users
WHERE user_id = ?
to any of SQL builders like JOOQ, QueryDsl just to get ability to modify query — add joins, additional "where" clauses, LIMIT-OFFSET?

Another option, I've used JSQLParser in the past for a project like this. It wasn't very difficult to use.

jOOQ's Parser
jOOQ's more recent versions have introduced a parser, which parses arbitrary SQL from all currently supported vendor dialects into the jOOQ expression tree. Once you have that expression tree, you can manipulate it to whatever you want using the VisitListener SPI.
For historic context:
For jOOQ, there exists a third-party contribution by Gudu Software called SQL 2 jOOQ, which can parse SQL SELECT statements written in either MySQL or PostgreSQL dialects and generate jOOQ code as output.

Related

Can I use JOOQ as an SQL parser?

I'm trying to parse a SELECT statement in Java. I'm familiar with JOOQ, and was hoping to use that. I know it's not explicitly designed as an SQL parser—it's actually a lot more than that, so I was thinking there might be a way to use its internal parsers to parse SELECT queries.
I saw some information on how to access some of JOOQ's internals using the Visitor pattern, but I need to navigate inside the query using a tree-like structure that will allow access to each part of the query individually. I don't want to use the Visitor pattern for all use cases.
Is this possible? How would I go about doing it?
Yes, you can. jOOQ has a parser that can be used:
Programmatically
As a CLI
Online, as a SQL dialect translator
As of jOOQ 3.17, there's an experimental model API which can be used to traverse your expression tree externally, e.g. using pattern matching, or internally using the new Traverser API. It is also still possible to traverse the expression tree using a VisitListener when rendering the expression tree back to SQL.
A full-fledged SQL parser is available from DSLContext.parser() and from DSLContext.parsingConnection() (see the manual's section about parsing connections for the latter).
The SQL Parsing API page gives this trivial example:
ResultQuery<?> query =
DSL.using(configuration)
.parser()
.parseResultQuery("SELECT * FROM (VALUES (1, 'a'), (2, 'b')) t(a, b)");
parseResultQuery is the method you need for a single SELECT query, use parse(String) if you may have multiple queries.

Is there a way to use redquerybuilder with Lucene?

Is there any interface to Lucene from redquery builder (https://github.com/salk31/RedQueryBuilder)? I have a Lucene indexed system and would like to support complex Lucene queries using its AND and NOT operators.
Alternatively, are there other visual query builders out there for Lucene that support "advanced search" functionality that include arbitrary numbers of AND/OR clauses?
As far as I know there isn't one that exists already.
I can think of two options:
* Use a SQL parser and serialiser to transform SQL into Lucence syntax (or query objects on the server)
* Use the 0.8.0 custom serialiser in RQB to produce Lucence query string. NB This is very experimental feature.
I should declare that I started the RQB project and that I love Lucence. Maybe worth raising a ticket for a feature? It could be a good way to test the serialisation if it produces Lucence queries rather than SQL?
NB If you want to store/re-load queries RQB is only designed to use SQL. It was chosen as a standard language to load/save even if never gets executed.

How to use native SQL as a fragment (where clause) of a bigger query made with Criteria API in Hibernate?

I have a following problem. In application, which I am developing, we use Hibernate and every query is written with Criteria API. Now, in some places, we want to add possibility for user to write some SQL code which will be used as part of where clause in a query. So basically, user can filter data displayed to him from database in his own way.
For a few days now, I am trying to find a way to modify our previous queries to acquire result described above. Here is what I know:
It looks like you cannot combine Criteria API with native SQL. You can either write whole query in SQL or use only criteria API. Is that right?
I am asking this question because it would be the easiest solution, just to use this SQL code as another predicate in where clause in our query. But I don't think it's possbile on this level.
I know on which table user wants to filter data. So I could just execute native SQL query and use result list as a parameter to IN clause in criteria query. But I don't know if it is efficient with many records in a result list.
So if I cannot do it on criteria API level, I thought that maybe I could somehow influence the SQL generetion process and put my SQL in a proper place but it seems to be impossible.
So my real question is: is it somehow possible to have access to SQL code of the query, after SQL generation phase but before actual execution of query? Just to manipulate with it manually? Can it be done safely and as far as possible simply?
Or maybe just try to parse this SQL written by user and use it in criteria query?
Changing existing criteria queries into native SQL queries is rather out of discussion.
Yes, you can get the SQL from the Hibernate criteria using the org.hibernate.loader.criteria.CriteriaQueryTranslator class.
This will allow you to append the additional SQL clause(s) to the end and execute it as a native SQL:
CriteriaQueryTranslator translator = new CriteriaQueryTranslator(factory, criteria, "myEntityName", CriteriaQueryTranslator.ROOT_SQL_ALIAS);
String select = translator.getSelect();
String whereClause = translator.getWhereCondition();
Personally though, if faced with this requirement I would shy away from accepting SQL from the end-user and give them a user interface to populate some type of filter object. This can then be converted into HQL criterion, which is much safer and doesn't tie your code as tightly to the database implementation.
Edit based on comments
Example of extracting SQL from a JPA query implemented with Hibernate:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<MyEntity> q = builder.createQuery(MyEntity.class);
Root<MyEntity> entity = q.from(MyEntity.class);
q.select(entity).orderBy(builder.desc(entity.get("lastModified")));
TypedQuery<MyEntity> query = entityManager.createQuery(q);
String sql = query.unwrap(org.hibernate.Query.class).getQueryString();
criteria.add(Restrictions.sqlRestriction(" AND ID in (1,2,3)" ));

Filtering in query using JPA in java

How to fetch data on the basis of YEAR using openjpa from database. I have a timestamp(RECEIPT_DATE) field in my database. Now i went to fetch the data from the database on the basis of selected year.
Query is as below:
select contact_names from contact where YEAR(RECEIPT_DATE)='2014'.
This works perfectly in database.
The same i wrote in JPA like this.
select contactNames from contact where year(receiptDate)='2014'.
But i get an error like Year Arguement cannot be recognized.
Is there any way to how can i perform the same query using JPA preferably not making use of any additional plugins for the same. Please guide.
You should use the JPA Criteria API Queries. They have functions to extract the year of a date. and it's helpful because if you make a mistake you know it on compile time instead on runtime.
JPA does not have the YEAR function, with JPA you will use JPQL and not SQL.
You could use NativeQuery instead:
entityManager.createNativeQuery("select * name from person", RESULT_CLASS.class);
http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html
JPA 2.1 has FUNCTION(funcName, args) and you can set the FUNCTION to YEAR (or whatever your RDBMS supports). It has no specific functions for date components, so you have to look up the specific native functions used by your RDBMS and put them into JPA2.1 "FUNCTION"

OpenJPA distinct on

In my DB schema I have conversations with several emails. I want to get the newest emails from a list of conversations. In PostgreSql the query:
select distinct on (conversation_id) *
from email
where conversation_id in (7085214, 7084964)
order by conversation_id, processing_date desc
OpenJPA:
(List<Email>) entityManager.createQuery("SELECT
distinct(email.conversation.id), email FROM Email email WHERE
email.conversation.id in :id ORDER BY email.conversation.id,
email.processingDate DESC").setParameter("id", conversationIds);
It gives back a map of the conversation ids and the whole list of emails in the conversations.
How could I make it right?
Thanks
Use native SQL.
The only other way to do what you want is to develop a patch to OpenJPA that "teaches" it how to use the PostgreSQL extension DISTINCT ON in its JPQL parser and query generator. Most ORMs accept such extensions via dialect hooks. Don't expect this to be a simple task, though - unless you're writing a lot of these queries, native SQL is almost certain to be much easier.
You can't just use DISTINCT or DISTINCT ON like functions. They aren't; they're completely separate syntax. A JPQL engine would try to convert it into a true function call that'd fail at runtime - or in the case of distinct on, just fail to parse it in the first place.
BTW, DISTINCT ON is a bit like GROUP BY in some other vendor databases like MySQL, where you're allowed to specify columns in the SELECT that don't appear in the GROUP BY or an aggregate. So in MySQL people probably do this by just producing a technically invalid query that MySQL accepts anyway - it's quite likely that the OpenJPA JPQL handler won't notice the problem, so it'll pass it through fine. This trick won't work for DISTINCT ON and PostgreSQL is strictly standards compliant about GROUP BY, it won't let you produce a non-deterministic query with GROUP BY.

Categories

Resources