I would like to rewrite an oracle stored procedure to java code, to select data with concatenated values in a query string to compare the following way:
Query qString =
"SELECT Obj " +
"FROM MyTable Obj2 WHERE ( Obj2.value1 || Obj2.value2 ) in " +
"(SELECT Obj2.value1 || MAX(Obj2.value2) FROM MyTable Obj2 WHERE Obj2.value2 >= :param GROUP BY Obj2.value1) " +
"ORDER BY Obj.value2, Obj.value1";
query = entityManager.createQuery(qString);
query.setParameter("param ", param );
When I run the query as a webservice on weblogic server I got error with the '|' character.
What can I use instead of the || operator to get the same result?
The Java Persistence Query Language provides the CONCAT() function, so you should be able to write Obj2.value1 || Obj2.value2 as CONCAT(Obj2.value1, Obj2.value2)
Related
I am using Oracle DB with Spring Boot Application. The query is working fine in DBeaver but not in actual application. I have copied the query from the console error message.
Query calling function:
public List<UserFullNameDesignationDto> getUserFullNameDesignation(String[] userNames) {
String queryParam = "";
for (String uName : userNames) {
queryParam += "'" + uName + "',";
}
queryParam = queryParam.substring(0, queryParam.length() - 1);
String sql =
"SELECT\n"
+ "\tu.USERNAME,\n"
+ "\tu.FULL_NAME,\n"
+ "\tcd.NAME \n"
+ "FROM\n"
+ "\tUSER_ENTITY u\n"
+ "LEFT JOIN CORE_DESIGNATIONS cd ON u.DESIGNATION_ID = cd.ID \n"
+ "WHERE\n"
+ "\tu.USERNAME IN ("
+ queryParam
+ ");\n";
var rowMapper = BeanPropertyRowMapper.newInstance(UserFullNameDesignationDto.class);
List<UserFullNameDesignationDto> list = jdbcTemplate.query(sql, rowMapper);
System.out.println(list);
return jdbcTemplate.query(sql, rowMapper);
}
Stack trace:
org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [SELECT
u.USERNAME,
u.FULL_NAME,
cd.NAME
FROM
USER_ENTITY u
LEFT JOIN CORE_DESIGNATIONS cd ON u.DESIGNATION_ID = cd.ID
WHERE
u.USERNAME IN ('aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1');
]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
............
Caused by: java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
This line will be
'aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1'
replaced by variable.
The root cause of the error is that you copied the semicolon in the JDBCTemplate statement (which works in SQL IDE but not in JDBC)
+ ");\n";
remove it
+ ")\n";
and it will work (or you get an other error;)
Anyway you should re-think your way of concatenation input in the SQL statement towards the usage of bind variables. There are lot of examples for binding IN list on this site.
As far as I can tell, you'll have to split values stored in that variable into rows. How? Like this:
SQL> with test(queryParam) as
2 (select q'['aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1']' from dual)
3 select regexp_substr(queryParam, '[^,]+', 1, level) val
4 from test
5 connect by level <= regexp_count(queryParam, ',') + 1
6 /
VAL
----------------------------------------------------------------------
'aro_user'
'afo_user1'
'afo_user1'
'afo_user1'
'afo_user1'
'afo_user1'
6 rows selected.
SQL>
It means that this:
+ "\tu.USERNAME IN ("
+ queryParam
+ ");\n";
should be modified so that queryParam is replaced by
( SELECT REGEXP_SUBSTR (queryParam,
'[^,]+',
1,
LEVEL) val
FROM test
CONNECT BY LEVEL <= REGEXP_COUNT (queryParam, ',') + 1)
List<String> userIds = Arrays.asList("User1", "User2");
String inSql = String.join(",", Collections.nCopies(userIds.size(), "?"));
List<User> employees = jdbcTemplate.query(String.format("SELECT * FROM Users WHERE id IN (%s)", inSql), userIds.toArray());
Please see, https://www.baeldung.com/spring-jdbctemplate-in-list for
I have an issue when executing the following SQL statement using JAVA on a ORACLE database, it works with DBeaver/SQLdeveloper but during the java process I get the following error. Any ideas ?
SQL Statement :
SELECT MIN(SUBSTR(t1.MONTH,1,4)) || 'A' || 'B' || 'CDE FGR' || ' ' || 'AT'
FROM table1 t1, table2 t2
WHERE t1.toto=t2.toto
AND t1.tata=t2.tata
AND t1.titi=t2.titi
AND t2.tutu = 'IMPACT_EUROPE_FLAG'
SQL error during java process :
org.springframework.jdbc.BadSqlGrammarException: Attempt to process next row failed; bad SQL grammar
nested exception is java.sql.SQLException: Invalid column name
Tables :
TABLE1 TABLE2
--------------
MONTH TOTO
TOTO TATA
TATA TITI
TITI TUTU
TUTU
My java process, only the reader and stepbuilder :
private Step insertBaseToFile() {
return stepBuilderFactory.get("insertBaseToFile").<GenericRecord, GenericRecord>chunk(100).reader(baseReader())
.writer(fileWriter()).build();
}
private JdbcCursorItemReader<GenericRecord> baseReader() {
JdbcCursorItemReader<GenericRecord> databaseReader = new JdbcCursorItemReader<>();
String sql = null;
sql = " SELECT MIN(SUBSTR(t1.MONTH,1,4)) || 'A' || 'B' || 'CDE FGR' || ' ' || 'AT' " +
"FROM table1 t1, table2 t2 " +
"WHERE t1.toto=t2.toto " +
"AND t1.tata=t2.tata " +
"AND t1.titi=t2.titi " +
"AND t2.tutu = 'IMPACT_EUROPE_FLAG'"
databaseReader.setDataSource(dataSource); //dataSource object from my class using JSON conf to get logs in to DB
databaseReader.setSql(sql);
return databaseReader;
}
My guess is that this is happening because the name of the column in your result is going to be:MIN(SUBSTR(T1.MONTH,1,4))||'A'||'B'||'CDEFGR'||''||'AT'
Try:
SELECT MIN( ... ) AS mycolumn
My bad.
Everything works well it was an error from me using wrong variables names.
I'm trying to create a Java named query which does the following postgres query:
select * from call_attempt where result is NULL and id like '0000000101%';
The 0000000101 is set to id in my code, so this is what I want to do, but it's malformed: (I'm not sure how to set the id field while using the % and it has to be inside ' ')
#NamedQuery(name = AttemptEntity.JQL.NOTENDED,
query = "SELECT ae FROM AttemptEntity ae WHERE ae.result IS NULL,"
+ " ae.correlationId LIKE '=:id%'")
First, you forgot the and, and replaced it by a comma.
Second, the % must be passed as part of the argument:
SELECT ae FROM AttemptEntity ae WHERE ae.result IS NULL
and ae.correlationId LIKE :id
And then, when executing the query:
String id = "0000000101%";
query.setParameter("id", id);
You can't have the % in the NamedQuery, but you can have it in the value you assign the parameter.
query.setParamter("id", 0000000101+ "%");
You also need to add AND and remove the comma after NULL.
Reference: Named Query with like in where clause
I have a query that will need to run 28 000 times in a row, so I thought using a preparedStatement probably is a clever idea.
Here is my query :
String requestWithFirstName = "SELECT SE.ELEMENT_ID, SE.LASTNAME||' '||SE.FIRSTNAME AS ELEMENT, (SCORE(1)+SCORE(2))/2 AS SCORE "
+ "FROM BL_SUSPICIOUS_ELEMENT SE "
+ "WHERE CONTAINS(SE.LASTNAME, 'fuzzy({' || ? || '},' || ? || ',' || ? || ', weight)' , 1)>0 "
+ "AND CONTAINS(SE.FIRSTNAME, 'fuzzy({' || ? || '},' || ? || ',' || ? || ', weight)' , 2)>0 "
+ (type > 0 ? "AND SE.ELEMENT_TYPE_ID = ?" : "")
+ " ORDER BY SCORE DESC";
Everthings worked fine until we realized that the fuzzy methods doesn't perform well for splitted words like 'pikachu is my hero' and it is advised to created, in this case, 4 fuzzy search for 'pikachu' 'is' 'my' 'hero'. Not sure if this is true, but as I will run the query 28 000 times it's a good opportunity to see it in action.
So I tried to modify the query in this manner :
"SELECT A.ELEMENT_ID, A.LASTNAME||' '||A.FIRSTNAME AS AKA, SCORE(1) AS SCORE "
+ "FROM BL_AKA A, BL_SUSPICIOUS_ELEMENT SE "
+ "WHERE CONTAINS(A.LASTNAME, ?, 1)>0 "
+ "AND SE.ELEMENT_ID = A.ELEMENT_ID "
+ (type > 0 ? "AND SE.ELEMENT_TYPE_ID = ?": "")
+ " ORDER BY SCORE DESC";
In this case, ? will be set to :
'fuzzy({Burnham},70,4,weight),fuzzy({Investors},70,4,weight),fuzzy({Trust},70,4,weight)'
The query seems fine, running on sql dev. However, with Java, I get the following error :
ORA-20000: Oracle Text error:
DRG-50900: text query parser error on line 1, column 30
DRG-50920: part of phrase not itself a phrase or equivalence
DRG-50900: text query parser error on line 1, column 30
DRG-50920: part of phrase not itself a phrase or equivalence
Any advice ?
I wonder if this is the same situation as the in statement (impossible to create a select * from pokemon where monster in (?))
Thanks !
When you use a prepared statement in java, it will set the parameter according to the method you use. So
String s = "'fuzzy({Burnham},70,4,weight),fuzzy({Investors},70,4,weight),fuzzy({Trust},70,4,weight)'";
statement.setString(s);
will be escaped again and results in:
'''fuzzy({Burnham},70,4,weight),fuzzy({Investors},70,4,weight),fuzzy({Trust},70,4,weight)'''
Try to set the parameter without the quotes.
You can create an IN (?) statement. But you will have to add a questionmark for every parameter: WHERE monster IN (?,?,?,?,?,?)...
I have created table with 3 fields language,country,install type. When I write a query to print the maximum occuring value in each of the field, I am getting a weird problem.Can anyone say the reason.Here is my code.
PreparedStatement ps1= null;
ps1 = conn.prepareStatement("desc Configuration");
ResultSet rs1=ps1.executeQuery();
while(rs1.next()) {
System.out.print(rs1.getString(1)+":");
PreparedStatement ps2= null;
ps2 = conn.prepareStatement("select ? from Configuration c1 "+
" group by language "+
" having count(*) >= all " +
" ( select count(*) from Configuration c2 "+
" group by language )");
ps2.setString(1,rs1.getString(1));
ResultSet rs2=ps2.executeQuery();
while(rs2.next())
System.out.print(rs2.getString(1));
System.out.println();
}
The output I am getting here is language:language But the output what I am expecting is
language:english like that. I am getting later output if i replace '?' with language in the prepare statement.But if i give the same with ? I am getting what ever I have given for ps2.setString.
Why is this happening. Any solutions?
? in prepared statements is not a placeholder for textual substitution, it's a parameter, therefore its value is always interpreted as data, not as an arbitrary part of query syntax.
So, in this case the actual query being executed is an equivalent of select 'language' from ....
If you need to substitute parts of the query other than data, you have to use concatenation (beware of SQL injections!):
ps2 = conn.prepareStatement("select "
+ rs1.getString(1)
+ " from Configuration c1 group by language having count(*) >= all( select count(*)from Configuration c2 group by language )");
You can't set column names using a PreparedStatement. You can only set column values.
Instead of using this approach, you will have to build the sql yourself using concatenation, for example:
String sql = "select "+ rs1.getString(1) + " from Configuration c1 group by language having count(*) >= all( select count(*)from Configuration c2 group by language)";
The '?' mark in ps2 is recognized as literal-string. Not as a column name.