VertX SQL queryWithParams Howto use LIKE ? with wildards - java

I'm working on a simple VertX Application. I have a hsqlDB and I'm trying to execute a query where I want to get all IDs from the Table where the Name contains a search parameter
String sql = "SELECT ID FROM MYTABLE WHERE NAME LIKE ?";
So this works when the Name is the same as the ?
When I try to use wildcards:
String sql = "SELECT ID FROM MYTABLE WHERE NAME LIKE %?%";
or
String sql = "SELECT ID FROM MYTABLE WHERE NAME LIKE '%?%'";
it doesn't work.
My Code:
private void getIDsBySearchString(String search, SQLConnection conn, Handler<AsyncResult<Vector<Integer>>> resultHandler) {
String sql = "SELECT ID FROM MYTABLE WHERE NAME LIKE ?";
conn.queryWithParams(sql, new JsonArray().add(search), asyncResult -> {
if(asyncResult.failed()) {
resultHandler.handle(Future.failedFuture("No Names Found"));
} else {
int numRows = asyncResult.result().getNumRows();
if(numRows >= 1) {
Vector<Integer> IDVector = new Vector<>();
for(int i = 0; i < numRows; i++) {
int id = asyncResult.result().getRows().get(i).getInteger("ID");
IDVector.add(id);
}
resultHandler.handle(Future.succeededFuture(IDVector));
} else {
resultHandler.handle(Future.failedFuture("No Names found"));
}
}
});
}
How do I need to edit my query String so the ? will be replaced by the search String and I will be able to use wildcards?

A parameter cannot be inside a quoted string. It can be part of a concat expression involving other strings.
String sql = "SELECT ID FROM MYTABLE WHERE NAME LIKE '%' || ? || '%'";

The part that should be changed is your search parameter, not the sql part:
String sql = "SELECT ID FROM MYTABLE WHERE NAME LIKE ?";
conn.queryWithParams(sql, new JsonArray().add("%"+search+"%"), asyncResult -> { ... }

Related

How can I get words from brackets in String?

I have various sql requests.For example
SELECT COUNT(project_id) AS 'count', project.name AS 'projects' FROM test
JOIN project ON project_id = project.id
or
SELECT count(*) AS 'browsers' FROM `test`
I want to receive words that are in ''. For example 'count', 'projects', 'browsers'.
Thus, I want to get the names of the columns from the table.But how can I do this, something I don't understand.So far I just wrote
String[] str = sqlRequest.split("FROM");
but what can I write next, I don’t guess. Tell me how you can get words from these brackets?
Don't do this with String split, replace etc. At some point, it will fail.
You should parse the sql statement. Example with JsqlParser like
public class Main {
public static void main(String[] args) throws JSQLParserException {
Select stmt = (Select) CCJSqlParserUtil.parse(
"SELECT COUNT(project_id) AS 'count', project.name AS 'projects' FROM test\n"
+ "JOIN project ON project_id = project.id ");
for (SelectItem selectItem : ((PlainSelect) stmt.getSelectBody()).getSelectItems()) {
selectItem.accept(new SelectItemVisitorAdapter() {
#Override
public void visit(SelectExpressionItem item) {
System.err.println(item.getAlias().getName());
}
});
}
}
}
Output:
'count'
'projects'
You can do it as follow:
String query = "SELECT COUNT(project_id) AS 'count', project.name AS 'projects' FROM test JOIN project ON project_id = project.id";
LinkedList<String> queryColumns = new LinkedList<>();
String[] test = query.replace("SELECT", "").split("FROM")[0].split(","); //You have a string from which you need to extract single names, taking care of aliases.
for(String s : test) {
int aliasIndex = s.indexOf("AS");
String column;
if(aliasIndex != -1) {
//if there is an alias
column = s.substring(aliasIndex + 2).replace("'","").strip();
} else {
//if there isn't an alias
column = s.replace("'","").strip();
}
queryColumns.add(column);
}
I assume that the alias is indicated as 'AS' in uppercase, if it can be lowercase too, it's easy to change and adapt the code.

jdbcTemplate query prepared statement with multiple parameters

I am building my sql string like this:
String sql = "SELECT * FROM horse WHERE 1=1 ";
if (horse.getName() != null) {
sql += "AND UPPER(name) LIKE ? ";
}
if (horse.getDescription() != null) {
sql += "AND UPPER(description) LIKE ? ";
}
if (horse.getRating() != null) {
sql += "AND rating=? ";
}
I want to find a match for entity depending on which parameters are passed. So if only name and rating are passed I would get something like: SELECT * FROM horse WHERE 1=1 AND UPPER(name) LIKE ? AND rating=?
Now I pass the sql string to query like this:
List<Horse> matchingHorses = jdbcTemplate.query(sql, new Object[]{horse.getName()}, mapHorse());
This returns a correct result but I have to pass to new Object[] {} only the parameters that I know that user is gonna pass or else I do not get anything. For example if user passes something like this:
{
"description":"desc"
}
I won't get any results even if there is a description with "desc". If I do this:
List<Horse> matchingHorses = jdbcTemplate.query(sql, new Object[]{horse.getName(), horse.getDescription(), horse.getRating()}, mapHorse());
and pass only name I get:
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [SELECT * FROM horse WHERE 1=1 AND UPPER(name) LIKE ? ];
Invalid value "2" for parameter "parameterIndex" [90008-200]; nested exception is org.h2.jdbc.JdbcSQLDataException: Invalid value "2" for parameter "parameterIndex" [90008-200]
Here is my mapHorse() row mapper:
private RowMapper<Horse> mapHorse() {
return (resultSet, i) -> {
Long horseId = resultSet.getLong("id");
String horseName = resultSet.getString("name");
String horseDesc = resultSet.getString("description");
int horseRating = resultSet.getInt("rating");
return new Horse(
horseId,
horseName,
horseDesc,
horseRating,
);
};
}
How do I implement this correctly?
You can use NamedParameterJdbcTemplate.
MapSqlParameterSource params = new MapSqlParameterSource();
if (horse.getName() != null) {
sql += "AND UPPER(name) LIKE :name ";
params.addValue("name", horse.getName());
}
if (horse.getDescription() != null) {
sql += "AND UPPER(description) LIKE :description ";
params.addValue("description", horse.getDescription());
}
if (horse.getRating() != null) {
sql += "AND rating=:rating ";
params.addValue("rating ", horse.getRating());
}
namedParameterJdbcTemplate.query(sql, params, mapHorse());
suggestion- better if you you use string builder.

How to retrieve records from db where a particular column is equal to a set of Strings?

I have a table T1 with columns ID(primary key,varchar), name(varchar), value(number) and key(number).I have a String array which consists of ID's and I want to retrieve all the records with those id in the String array from TABLE T1 in a single query. How can I write this query in oracle?
I'm currently using a for loop and getting the records:
for(String id: idList)
{
//Query to get record one by one (Select * from t1 where ID='id')
}
Could you suggest me a query to retrieve all these values in a single query?
Use the following query
select * from t1 where id in ('id1', 'id2', 'id3')
To get the ArrayList into the format, do the following
StringBuilder sb = New StringBuilder();
for(String id: idList)
{
sb.append("'"+id+"',")
}
sb.deleteCharAt(sb.length() -1);
sb.toString();
//Prep the query string
//---------------------------------
$strQ ="";
$len = count($idList);
$strQ = "'".$idList[0]."'";
for($i=1; $i<$len; $i++){
$strQ += " or ID = '".$idList[$i]."'";
}
//Now Da Query
//---------------------------------------
"Select * from t1 where ID= ".$strQ;
//---------------------
I've explained da above using PHP...
Try this
List<Long> itemIDs = new ArrayList<Long>();
itemIDs.add(10);
....
....
AuthService.deletePracticeAppMenu(itemIDs, selectedPractice.getID());
public void deletePracticeAppMenu(List<Long> prAppMenuIDs, Long practiceID) {
String query = "delete from PracticeAppMenu where PrAppMenuID in (:appMenuIDs) and practiceID = :pracid ";
Query q = getCurrentSession().createQuery(query);
q.setParameterList("appMenuIDs", prAppMenuIDs);
q.setParameter("pracid", practiceID);
q.executeUpdate();
}

JdbcTemplate does not support Parameterized Query 'IN' case? Must by NamedParameterJdbcTemplate?

Aimed at preventing SQL injection attacks, all the SQL Statement code in my project should transformed to Parameterized Query. But I got a problem when the query condition includes a 'IN' case. Like this (Using DB2 database):
String employeeId = 'D2309';
String name = "%brady%";
List<Integer> userRights = new ArrayList<Integer>();
userRights.add(1);
userRights.add(2);
userRights.add(3);
String sql = "SELECT * FROM T_EMPLOYEE WHERE EMPLOYEE_ID = ? AND NAME LIKE ?
AND RIGHT IN (?)";
jdbcTemplate.query(sql, new Object[] {employeeId, name, userRights}, new
EmployeeRowMapper());
The above code runs failed with the exception:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad
SQL grammar [SELECT * FROM T_EMPLOYEE WHERE EMPLOYEE_ID = ? AND NAME LIKE ? AND
RIGHT IN (?)]; nested exception is com.ibm.db2.jcc.am.io: [jcc][1091][10824]
[3.57.82] .... ERRORCODE=-4461, SQLSTATE=42815
The question here is that does not JdbcTemplate support Parameterized Query for IN case? and I know this work can be done by NamedParameterJdbcTemplate, and whether only NamedParameterJdbcTemplate can do IN case query?
Thanks a lot.
As I already mentioned in the comments, I'm not happy with this solution as it dynamically generates a number of SQL statements. Given the number of userRights is between 1 and n, it requires up to n prepared statements in the cache.
The below should work (I did not try it).
String employeeId = 'D2309';
String name = "%brady%";
List<Integer> userRights = new ArrayList<Integer>();
userRights.add(1);
userRights.add(2);
userRights.add(3);
// build the input string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < userRights.size; i++) {
sb.append("?");
if (i < userRights.size() - 1) {
sb.append(", ");
}
}
// build the SQL
String sql = "SELECT * FROM T_EMPLOYEE WHERE EMPLOYEE_ID = ?" +
" AND NAME LIKE ?" +
" AND RIGHT IN (" + sb.toString() + ")";
// init the object array
// size is employeeId + name + right
Object[] param = new Object[2 + userRights.size()];
// fill it
param[0] = employeeId;
param[1] = name;
for (int i = 0; i < userRights.size(); i++) {
param[i + 2] = userRights.get(i);
}
jdbcTemplate.query(sql, param, new EmployeeRowMapper());

how to generate sql query dynamically having specific colums

I have several tables. I have a query also. My problem is to generate the SQL query dynamically using Java.
I have the following fields in a separate table:
Collumn name status
po_number, Y
unit_cost, Y
placed_date , Y
date_closed, Y
scheduled_arrival_date Y
date_closed Y
order_quantity Y
roll_number N
product_sku N
product_category_name N
rec_vendor_quantity Y
vendor_name Y
et_conversion_unit_quantity Y
from which i have to generate a query when the status is Y, the problem here is some time the above columns
The following query is the out put of the above :
here i have inculded all the columns but i have to exculde the column which has the status of N, please help me to construt the query using java.
select
pi.po_number,poi.unit_cost,pi.placed_date CreateDate,
case when isnull(pi.date_closed) then pi.scheduled_arrival_date
else pi.date_closed end as ReceviedDate,
poi.order_quantity,poi.roll_number,p.product_sku product_name,
pc.product_category_name,poi.rec_vendor_quantity,pv.vendor_name,p.et_conversion_unit_quantity,pi.note
from
purchase_order as pi,
purchase_order_inventory as poi,
product_vendors as pv,
products AS p,
product_categories AS pc
where
pi.purchase_order_id=poi.purchase_order_id and
pc.product_category_id=p.product_category_id and
poi.product_id = p.product_id and
poi.product_category_id=pc.product_category_id and
pi.vendor_id=pv.product_vendor_id and
( ( pi.date_closed >= '2012-01-01' and pi.date_closed <='2012-09-05 23:59:59' )
or ( pi.scheduled_arrival_date >= '2012-01-01' and pi.scheduled_arrival_date <='2012-09-05 23:59:59') ) and
pi.po_type=0
and pi.status_id = 0 and poi.transaction_type = 0
order by pi.po_number
UPDATE :
QUERY : STEP 1:
SELECT rcm.id,rcm.tablename,rcm.columnname,rcm.size,rcm.displayorder,rcm.isactive FROM report_customise_master rcm where rcm.tablename !='employee' and rcm.isactive='Y' order by rcm.displayorder;
STEP 2 :
Java method to construct the query :
public Map getComplexReportQuery() {
String query = "SELECT rcm.id,rcm.tablename,rcm.columnname,rcm.size,rcm.displayorder,rcm.isactive FROM report_customise_master rcm where rcm.tablename !='employee' and rcm.isactive='Y' order by rcm.displayorder;";
String tableName = "", from = "", select = "";
StringBuffer sb = new StringBuffer();
Map<String, List<String>> resultsMap = new LinkedHashMap<String, List<String>>();
Map<String, String> displayOrderMap = new LinkedHashMap<String, String>();
Map queryMap = new LinkedHashMap();
if (!query.isEmpty() || query.length() > 0) {
sb.append(query);
}
Connection connection = getConnection();
if (connection != null) {
try {
PreparedStatement reportQueryPS = connection.prepareStatement(sb.toString());
ResultSet reportQuery_rst = reportQueryPS.executeQuery();
List<String> tables = new ArrayList<String>();;
if (reportQuery_rst != null) {
StringBuilder selectQuery = new StringBuilder(" SELECT ");
StringBuilder fromQuery = new StringBuilder(" FROM ");
while (reportQuery_rst.next()) {
tableName = reportQuery_rst.getString("tablename");
List<String> columns = resultsMap.get(tableName);
if (columns == null) {
columns = new ArrayList<String>();
resultsMap.put(tableName, columns);
}
columns = resultsMap.get(tableName);
String columnName = reportQuery_rst.getString("columnname");
columns.add(columnName);
}
tableName = "";
for (Entry<String, List<String>> resultEntry : resultsMap.entrySet()) {
tableName = resultEntry.getKey();
List<String> columns = resultEntry.getValue();
int i = 0;
for (String column : columns) {
selectQuery.append(tableName + "." + column);
if (i != columns.size()) {
selectQuery.append(",");
} else {
selectQuery.append("");
}
i++;
}
if (!tables.contains(tableName)) {
tables.add(tableName);
}
}
//to remove comma at the end of line
select = selectQuery.toString().replaceAll(",$", "");
tableName = "";
int i = 0;
for (String table : tables) {
fromQuery.append(table);
fromQuery.append(" ");
fromQuery.append(table);
if (i != tables.size()) {
fromQuery.append(",");
} else {
fromQuery.append("");
}
i++;
}
from = fromQuery.toString().replaceAll(",$", "");
queryMap.put("query", select + from);
}
//from = from+"ORDER BY "+orderbyColumn+" "+sort+" ";
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
closeConnection(connection, null, null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
} else {
System.out.println("Connection not Established. Please Contact Vendor");
}
return queryMap;// return the map/ list which contains query and sory and display order
}
STEP 3 : Result query
{query= SELECT purchase_order.po_number,purchase_order.placed_date,purchase_order.date_closed,purchase_order.scheduled_arrival_date,purchase_order_inventory.unit_cost,purchase_order_inventory.order_quantity,purchase_order_inventory.roll_number,purchase_order_inventory.rec_vendor_quantity,products.product_sku,products.et_conversion_unit_quantity,product_categories.product_category_name ,product_vendors.vendor_name FROM purchase_order purchase_order,purchase_order_inventory purchase_order_inventory,products products,product_categories product_categories,product_vendors product_vendors}
but this not what i wanted, Please help me to construct the query i have given.
Two queries
You need to make two queries:
Query which fields are enabled
Build the second query string (the one you want to build dinamically)
It's this way because a SQL query has to tell which columns will be included before querying any data. In fact it will be used to build the internal DB query plan, it is, the way the DB motor will use to retrieve and organize the data you ask.
Query all columns
Is it necesary to query only that fields? Can't you query everything and use the relevant data?
Joins
Looking at the updated question I guess you need to dynamically add where conditions to join tables correctly. What I should do is have a reference telling me what coindition to add when a table is present.
There are at least two options:
Based on table pairs present (by example: "if A and B are present then add A.col1 = B.col2")
Based on tables present ("if B is present, then add A.col1 = B.col2; A should be present"
Based on your example I think the second option is more suitable (and easy to implement).
So I should have some static Map<String, JoinInfo> where JoinInfo has at least:
JoinInfo
+ conditionToAdd // by example "A.col1 = B.col2"
+ dependsOnTable // by example "A" to indicate that A must be present when B is present
So you can use:
that info to add tables that should be (by example: even if A has no selected cols, must be present to join with B)
include the conditionToAdd to the where clause
Anyway... I think you are getting into much trouble. Why so dynamic?
You have to approach the thing step by step.
Firstly you have to create a query that will return all rows that have status='Y'
Then you will put the COLUMN_NAME in a list of Strings.
List<String> list = new List<String>();
while(rs.next()){
list.add(rs.getString(columnNumber));
}
And then you have to loop the List and generate dynamically your second sql statement
String sqlSelect = "SELECT ";
String sqlFrom = " FROM SOME_OTHER_TABLE "
String sqlWhere = " WHERE SOME_CONDITION = 'SOME_VALUE' "
for(String x : list){
sqlFrom += x +" , "+;
}
//here make sure that you remove the last comma from sqlFrom because you will get an SQLException
String finalSql = sqlSelect + sqlFrom + sqlWhere ;

Categories

Resources