Smarter way of constructing query - sql

In my node.js module, I have some data in an array which I need to construct a query:
var valueClause = "(fieldA = '" + data.fieldA + "' AND fieldB = '";
var whereClause = ' WHERE ';
var hasAdded = false;
data.accounts.forEach(function (account) {
whereClause += valueClause + account.fieldB + "') OR ";
hasAdded = true;
})
if (hasAdded) {
// remove OR
whereClause = whereClause.substring(0, whereClause.length - 3);
// use the whereClause in the query
...
}
At the end of the above codes, if I have 2 accounts, I have whereClause:
' WHERE (fieldA = 'abcde' AND fieldB = '0003') OR (fieldA = 'abcde' AND fieldB = '0002') OR
I always have to remove the last ' OR' bit.
Is there a smarter way to construct the above?

Since the value of fieldA seems to be fix in the loop you could write this query
WHERE fieldA = 'abcde' AND fieldB IN ('0002','0003')
Since you have no prepared SQL Statement, where you could use the Array directly, you have to join the values similar to yout approach.
If guaranteed at lest one value exists I concatenate in the loop always with leading comma and use substr(1) of the value

Related

How to create a dynamic query using collection-valued named parameters?

As the title suggests, i'm currently trying to add parts to the JPQL-query using collection-valued named parameters (:queryLst).
Function call:
List<PanelSet> psetLst = setRepository.getMaxZchnrGroupByLeftEight(p.getCustomerNumber(), p.getDrawingNumber(), queryLst);
queryLst:
// Is used to store values from scanned and convert them into parts of a query
ArrayList<String> queryLst = new ArrayList<>();
for (int i = 0; i < size1; i++) {
scanEdvRev = scanned.get(i).toString();
queryLst.set(i, "and left(a.drawingnumber, 8) != left('" + scanEdvRev + "', 8)");
}
SetRepository:
public interface SetRepository extends CrudRepository<PanelSet, Integer> {
#Query("select distinct max(a.drawingNumber) from PanelSet a "
+ "where a.customerNumber = :customerNumber "
+ "and a.drawingNumber != :drawingNumber (:queryLst) "
+ "group by left(a.drawingNumber, 8)")
List<PanelSet> getMaxZchnrGroupByLeftEight(#Param("customerNumber") String customerNumber,
#Param("drawingNumber") String drawingNumber,
#Param("queryLst") ArrayList<String> queryLst);
}
When i run the project i get the following exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ( near line 1, column 159 [select distinct max(a.drawingNumber) from com.asetronics.qis2.model.PanelSet a where a.customerNumber = :customerNumber and a.drawingNumber != :drawingNumber (:queryLst) group by left(a.drawingNumber, 8)]
I'm unsure whether my approach to this problem is the correct way of doing this and whether this exception is caused by a simple syntax error or by my usage of collection-valued named parameters.
I've followed this guide trying to solve the problem.
EDIT: I'm basically trying to add each String from ArrayList<String> queryLst to the parametrized query inside setRepository.
#Query("select distinct max(a.drawingNumber) from PanelSet a "
+ "where a.customerNumber = :customerNumber "
+ "and a.drawingNumber != :drawingNumber (:queryLst) "
+ "group by left(a.drawingNumber, 8)")
If successful, the query behind the function
List<PanelSet> getMaxZchnrGroupByLeftEight(#Param("customerNumber") String customerNumber,
#Param("drawingNumber") String drawingNumber,
#Param("queryLst") ArrayList<String> queryLst);
should look like this:
queryStr = "select distinct max(a.drawingNumber) from PanelSet a "
+ "where a.customerNumber = " + customerNumber + ""
+ "and a.drawingNumber != " + drawingNumber + "";
for (String s : queryLst) {
queryStr = queryStr + s;
}
queryStr = queryStr + " group by left(a.drawingNumber, 8)";
I hope this clarifies what i'm trying to do with queryLst.
It can't be done using your approach of passing in a list of query chunks.
The closest you'll get is by adding every possible condition to the query and provide values for all those conditions in a way that allows conditions to be ignored, typically by providing a null.
You code might look like this:
#Query("select distinct max(a.drawingNumber) from PanelSet a "
+ "where a.customerNumber = :customerNumber "
+ "and a.drawingNumber != :drawingNumber "
+ "and a.myTextColumn = coalesce(:myTextColumn, a.myTextColumn) "
+ "and a.myIntegerColumn = coalesce(:myIntegerColumn, a.myIntegerColumn) "
// etc for all possible runtime conditions
+ "group by left(a.drawingNumber, 8)")
List<PanelSet> getMaxZchnrGroupByLeftEight(
#Param("customerNumber") String customerNumber,
#Param("drawingNumber") String drawingNumber,
#Param("myTextColumn") String myTextColumn,
#Param("myIntegerColumn") Integer myIntegerColumn);
Passing null for myTextColumn or myIntegerColumn will allow that column to be any value (except null).
You'll have to find SQL that works for the type of conditions you have and the data type of the columns involved and whether nulls are allowed.
If passing nulls doesn't work, use a special value, perhaps blank for text columns and some "impossible" date like 2999-01-01 fir date columns etc and code the condition like:
and (a.myCol = :myCol or :myCol = '2999-01-01')

Eclipselink NamedNativeQuery pass column name as parameter and not a value

Trying to pass column name as parameter but JPA sets it as a value surrounding it with single quotes.
#NamedNativeQueries({
#NamedNativeQuery(
name = "Genre.findAllLocalized",
query = "SELECT "
+ " CASE "
+ " WHEN ? IS NULL THEN genre_default"
+ " ELSE ? "
+ " END localized_genre "
+ "FROM genre ORDER BY localized_genre")
})
Then:
List<String> res = em.createNamedQuery("Genre.findAllLocalized")
.setParameter(1, colName)
.setParameter(2, colName)
.getResultList();
The problem is that the column names being passed are taken as values so the result will return result list with repeated values of "col_name" instead of selecting the value of the column passed as parameter.
Is this achievable?
Basically it makes no sense to create a prepared query like this, how would you name that query anyway: "*"? So the short answer is: no.
But you could create named queries dynamically if this matches your requirement:
String colName = "colName";
String query = "SELECT WHEN " + colName + " IS NULL THEN genre_default";
Query query = entitymanager.createQuery(query);
Probably using a criteria builder is more the way you want to use JPA (code from https://en.wikibooks.org/wiki/Java_Persistence/Criteria):
// Select the employees and the mailing addresses that have the same address.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
Root address = criteriaQuery.from(MailingAddress.class);
criteriaQuery.multiselect(employee, address);
criteriaQuery.where( criteriaBuilder.equal(employee.get("address"), address.get("address"));
Query query = entityManager.createQuery(criteriaQuery);
List<Object[]> result = query.getResultList();

pass object to IN Operator without single quote

Select * from table_A WHERE name in (#nameObj)
My issue is I am passing this object from code behind as
#nameObj = "'" + "john" + "'" + "," + "'" + "joseph" + "'"
So I want my final query like this:
Select * from table_A WHERE name in ('john','joseph')
But it is giving query like this:
Select * from table_A WHERE name in ('''john'',''joseph''')
This work for me
sql = $#" AND Office IN ('{string.Join("','", new string[] { "aa", "bb"})}')";
But you should pass this as sql parameter;
in sql query you have
AND Office IN (#datain)
and in call query
_dbContext.Offices.FromSql(sql,
new NpgsqlParameter(
"#datain",
$#"'{string.Join("','", new string[] {"aa", "bb"})}')")
)
.ToList();

Criteria query equivalent for native query

how to create criteria query for this native query?
SELECT u FROM Users u WHERE u.userStatus = 0 AND u.firstName LIKE " + "'" + username + "%" + "'"
Am I doing right?
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Users> criteriaQuery = criteriaBuilder.createQuery(Users.class);
Root<Users> root = criteriaQuery.from(Users.class);
List<String> names = Arrays.asList("Manager", "Sr. Manager");
Predicate predicate1=criteriaBuilder.like((root.get("firstName")), username+"%");
criteriaQuery.select(root).where(predicate1).where(root.get("designation").in(names));
Result:
System considering last where condition.

SQL Server advanced sorting out

I am an asp.net web pages developer I am developing a website in which I need advanced sorting like www.olx.com which is a classifieds website but the problem is that I have more than 25 categories I am using SQL Server & have my tables broken into parts.
Now, as I have many categories so when i sort them for example if I search for samsung but at the same time I want to sort search data by price (high to low or low to high) & also at same time I want to filter data which has a description now I would need to make 100's of queries by using if's but is there a more convenient solution to this problem
Currently I am using this query:
sql = "SELECT * FROM users_table INNER JOIN response_table ON users_table.ID = response_table.ID LEFT OUTER JOIN miscellaneous_table ON users_table.ID = miscellaneous_table.ID LEFT OUTER JOIN response_table2 ON users_table.ID = response_table2.ID";
sql = sql + " where response_table.sub_category='" + incat + "'";
if (Request["search"] != "" && Request["search"] != null)
{
var search = Request["search"].Trim();
string[] querynew = search.Split(' ');
var searchquery = " and ";
foreach (string word in querynew)
{
searchquery += " users_table.adtitle LIKE '%" + word + "%' OR ";
}
sql = sql + searchquery.Remove(searchquery.Length - 4);
}
if (Request["min"] != "" && Request["min"] != null && Request["max"] != null && Request["max"] != "")
{
sql = sql + " and (CAST(response_table.price AS Float)) between " + Request["min"].Trim() + " AND " + Request["max"].Trim();
}
Thanks
You can use this short hand in the WHERE clause
Assuming your filter are #col1, #col2, #col3
SELECT ...
FROM ...
WHERE (#col1 = 0 OR col1 = #col1)
AND (#col2 = '' OR col2 = #col2)
AND (#col3 = 0 OR col3 = #col3)
So with the above where clause, if the user only supply filter for col2 then just pass 0 in for col1 & col2 and it will unfilter these.