Does anyone know about a SQL statements parser, in Java, that would allow having an Object representation of a SQL query, allow modifying this representation and generate back the updated SQL statement?
Regards,
Christophe
I would think that ANTLR would be able to do this.
Maybe you could look at JSqlParser.
This is a demo use Java SQL Parser do something like this:
Input SQL:
SELECT A as A_Alias, B AS B_Alias FROM TABLE_X
If you need to remove the second column “B AS B_Alias” from the select list, just do something like this:
columns.removeResultColumn(1); // 0 is the first column
then you will get this new SQL(the , was removed automatically):
SELECT A as A_Alias FROM TABLE_X
this demo also illustrates how to replace a column, Add criteria (where clause), Add Order by clause and etc.
Related
I have some task to do and can't figure out how to reach the result.
For example i have some STRING like this :
key1=value1&key2=value2|key3=value3
This string like key=value with options AND or OR.
I have also some map that contains following things:
key1=ke1Mapped; key2=key2Mapped; key3=key3Mapped;
I want to build some sql Select * from table1 where
And insert mapped keys and its values, but also to take into account & and | , i.e. AND or OR to use in sql query when it's needed.
Actually, finally sql query should be:
Select * from table where ke1Mapped=value1 AND key2Mapped=value2 OR key3Mapped=value3
I tried to split the main string and convert to MAP and then to loop over the list of mapped values and build dynamically sql. But i don't know what is AND or OR.
Tried to push it in two stacks , also were complicated.
I try now to understand how to build only architecture of this flow. And can't figure out what approach is needed here.
Anyone can suggest something?
Thanks
Ok, just to cut it short, I've done the actual JPQL without using any parameter first and it looks like this.
SELECT count(dt)
FROM transaction dt
WHERE dt.transactionType = 'TEST'
AND dt.date
BETWEEN FUNC('TO_DATE','01-2019','mm-yyyy')
AND FUNC('TO_DATE','02-2019','mm-yyyy')
This thing work! But the thing is now I need to make the transactionType and date as a parameter and this is how it looks like
SELECT count(dt)
FROM transaction dt
WHERE dt.transactionType = :transType
AND dt.date
BETWEEN FUNC('TO_DATE',:lastMonth,'mm-yyyy')
AND FUNC('TO_DATE',:nextMonth,'mm-yyyy')
So for :transType it's fine, but inside this FUNC() seems like I shouldnt put the parameter just like that and need some workaround. I've been googling and can't find any result.
The error was like this
You have attempted to set a parameter value using a name of
lastMonth,'mm-yyyy') that does not exist in the query string
As you can see, the parameter inside FUNC() take along the parameter behind it that meant for FUNC(). What did I miss? Enlighten me please.
Make sure you're using setString for the parameter type.
I always had difficulty with named parameters within JPA, depending upon how the query was created - try using ordinal parameters, eg: ?1 and set them by index.
I'd avoid FUNC as it can carry some major overhead if you're not extremely careful.
There's a workaround for this problem.
Initially, the simplified SQL as below:
SELECT count(*)
FROM table tb
WHERE tb.date between to_date('01-2020','mm-yyyy') and to_date('02-2020','mm-yyyy');
And by directly convert the simplified SQL to JPQL, it turns out as such:
SELECT count(tb)
FROM table tb
WHERE tb.date BETWEEN FUNC('TO_DATE','01-2020','mm-yyyy') AND FUNC('TO_DATE','02-2020','mm-yyyy')
But, the JPQL need to be dynamic as the date will not be static, so by using JPQL parameter to ensure this JPQL can be used at any date, instinctively I thought to use as such:
SELECT count(tb)
FROM table tb
WHERE tb.date BETWEEN FUNC('TO_DATE',:fromDate,'mm-yyyy') AND FUNC('TO_DATE',:toDate,'mm-yyyy')
But as my initial question when this thread first started, such JPQL will not work. So how did I found a workaround? Relatively quite simple actually.
Instead of using this to get the ranging date (as from sql wise I use to_date)
WHERE tb.date BETWEEN FUNC('TO_DATE','','') AND FUNC('TO_DATE','','')
I used this
WHERE FUNC('TO_CHAR','','') between (--fromDate) and (--toDate)
Which finally resulted in final working JPQL of
SELECT count(tb)
FROM table tb
WHERE FUNC('TO_CHAR',tb.date,'mm-yyyy') BETWEEN (:fromDate) AND (:toDate)
In mysql I want to execute a query like this
SELECT MIN(id) FROM table;
The more I read about JOOQ syntax and the aggregate functions, the confused I get.
I thought something like this would work
select( EVENT.EVENTID , min() ).from( EVENT ).fetch();
or
Result<Integer> er = context.select( EVENT.EVENTID.min()).fetch();
I tried a work around by selecting the whole first record
Result<EventRecord> er2 = context.selectFrom(EVENT).orderBy(EVENT.EVENTID.asc()).limit(1).fetch();
If the result has size 0, a record does not exist, but when it is not 0 I get the right record. I would like to use the min() function but can't get the syntax right.
The query you want to write in SQL is this one:
SELECT MIN(event.eventid) FROM event
This is why your two attempts didn't work
// 1. You cannot combine single columns with aggregate functions in SQL,
// unless you're grouping by those columns
// 2. You didn't pass any cargument column to the MIN() function
context.select( EVENT.EVENTID , min() ).from( EVENT ).fetch();
// 3. This doesn't specify any FROM clause, so your database won't know what
// table you want to select the MIN(eventid) from
context.select( EVENT.EVENTID.min()).fetch();
Note that these thoughts are not specific to jOOQ, they are related to SQL in general. When using jOOQ, always think of the SQL statement you want to express first (the one at the top of my answer). So your jOOQ statement would look like any of these:
// "Postfix notation" for MIN()
context.select(EVENT.EVENTID.min()).from(EVENT).fetch();
// "Prefix notation" for MIN(), where min() is static-imported from
// org.jooq.impl.DSL
context.select(min(EVENT.EVENTID)).from(EVENT).fetch();
It looks like the fetchAny() method will return the record with the first/lowest record id.
EventRecord record = context.selectFrom(EVENT).fetchAny();
As #LukasEder mentioned there are many alternative methods, and he may be generous and follow up on some of those. Thanks Lucas
What (tool, library, way) can you recommend for parsing SQL query in Java?
I need to change column names in output, so for example:
I want to change query from:
SELECT a AS one, b AS two FROM xyz ORDER BY 1
to
SELECT a AS one_1, b AS two_2 FROM xyz ORDER BY 1
There might be many queries in one file to parse.
I tried using JSqlParser, but it doesn't support UTF-8 in SQL statements.
JSqlParser comes to mind. Never used it, but seems to fit the bill pretty well.
I am comparing 2 resultsets, and I have to update one resultset according to the data in another. I can do this easily using updateRow (or insertrow, if required). But I also need to generate sql query (preferably with oracle syntax) and add into an sql file, which gives me the option of updating that later. Can anyone tell me an elegant way of doing this?
Not exactly sure what you are looking to do, but I believe you are looking to update one table with data from another, or insert missing data into the first table when it is in the second. The easiest way to do this would be to use a merge:
merge into t1
using t2
on (t2.id = t1.id)
when matched
then
update
set t1.col1 = t2.col1,
t1.col2 = t2.col2,
t1.col3 = t2.col3
when not matched
then
insert
(t1.id, t1.col1, t1.col2, t1.col3)
values
(t2.id, t2.col1, t2.col2, t2.col3);
It should be noted that t2 can be replaced with a select statement, in case your new data isn't already stored in a table in the correct format.
If this is not what you are looking for, can you please clarify what you mean (an example of current data and desired output would be ideal).