How to check if a pair exists using HQL in query? - java

I have a list of different ids and their names. For every id[0] we have name[0] that needs to be matched.
list of ids, l{1,2,3,4};
list of names, n{a,b,c,d};
Now suppose if I want to get an exact match for both above combination, is there any way in HQL to get the result?
I am looking to find a replacement for a query like:
select any_column
from table_name
where (id[0]=1 and name[0]=a) or (id[1]=2 and name[1]=b and so on...);
The HQL query should be something like below:
select any_column
from table_name
where (id,name) IN {(id[0],name[0]), (id[1], name[1]),...};
Any suggestions?

I am not hql/sql guy, however one way I can think of is, in your hql, you concatenate the id and name with a space (or other special char) then with in sub-clause. something like:
select * from table where concat(id, ' ', name) in (:pairList)
The pairList parameter is a java collection, you should prepare before the hql query call, which has element id[x] + " " + name[x].
I think this should work.
If you are using hibernate, another possible solution is, make use of the hibernate's #Formular annotation on your table entity, to create a calculated column, such as:
#Formula(value = " concat(id, ' ', name) ")
private String idNamePair;
Then you can in hql use it as a normal field. like ... from table where idNamePair in (:paramList)

Related

Dynamic column name using prepared statement + sql query with variable containing 's

My query
attributes.replace(" ' ", "");
//also used SET "+attributes+"
String sql;
sql = "UPDATE diseaseinfo"
+ " SET ?=?"
+ "WHERE companyname = 'mycom' && diseaseName =?";
PreparedStatement preparedStmt = connects.prepareStatement(sql);
preparedStmt.setString(1, attributes);
preparedStmt.setString(2, attrData);
preparedStmt.setString(3, medname);
System.out.println(preparedStmt);
it is giving me an error because query set the column name in string so it become like this on causes
UPDATE diseaseinfo SET 'causes'='abc' WHERE companyname = 'mycom' and diseaseName ='fever'
and through this question I get to know that I can't add dynamic column by prepared statement: https://stackoverflow.com/a/3136049/7794329
Now, the real question comes up: suppose if I will use a simple update query like in this question: jdbc dymanic sql query with variable containg 's
It says you can't enter value with 's in your simple sql query because it will again make the query syntactical error for example :
SELECT * FROM diseaseinfo WHERE diseaseName = 'Adult Still's disease' AND name = 'add';
Here it wont execute because of ' 's on 'Adult Still's
Then it won't work with simple query. What should I do now? What to use? To set dynamic column with taking care of 's in the query.
I am not worried about SQL injection because i am working on local. And I just want my query to be executed.
Right. We can't supply identifiers as bind parameters. The name of the column has to be part of the SQL text.
We can dynamically incorporate the name of the column into the SQL text with something like this:
sql = "UPDATE diseaseinfo"
+ " SET `" + colname + "` = ?"
+ " WHERE companyname = 'mycom' AND diseaseName = ?";
And supply values for the two remaining bind parameters
preparedStmt.setString(1, attrData);
preparedStmt.setString(2, medname);
And you are absolutely correct about being concerned about SQL Injection.
Supplied as bind values, single quotes in the values of attrData and medname won't be an issue, in terms of SQL Injection.
But the example I've provided is vulnerable through incorporating the colname variable into the SQL text, if we don't have some guaranteed that colname is "safe" to include in the statement.
So we need to make the assignment of a value to colname "safe".
Several approaches we can use do that. The most secure would be a "whitelist" approach. The code can ensure that only specific allowed "safe" values get assigned to colname, before colname gets included into the SQL text.
As a simple example:
String colname;
if (attributes.equals("someexpectedvalue") {
colname = "columnname_to_be_used";
} else if (attributes.equals("someothervalid") {
colname = "valid_columname";
} else {
// unexpected/unsupported attributes value so
// handle condition or throw an exception
}
A more flexible approach is to ensure that a backtick character doesn't appear in colname. In the example, the value of colname is being escaped by enclosing it in backticks. So, as long as a backtick character doesn't appear in colname, we will prevent a supplied value from being interpreted as anything other than as an identifier.
For a more generic (and complicated) approach to using hardcoded backtick characters, we could consider making use the supportsQuotedIdentifiers and getIdentifierQuoteString methods of java.sql.DatabaseMetaData class.
(In the OP code, we don't see the datatype of contents of attributes. We see a call to a method named replace, and the arguments that are supplied to that. Assuming that attributes is a String, and that's supposed to be a column name, it's not at all clear why we would have "space single quote space" in the string, or why we need to remove that. Other than this mention, this answer doesn't address that.)

How to separate between data selecting from multiple tables?

I want to search in 16 different tables, but I don't wanna repeat the "select from DB" 16 times; I think that's not really help in performance!!!
I am using:
query="SELECT * FROM table1, table2,..., table16 WHERE id=?";
Is it correct ??
my problem is how to separate between data of tables ??
also maybe I can get from one table two or more results for one "id"; So I want to know which data is from which table !!
.
Best regards,
Your query will not work, because you are trying to join those multiple tables, whereas what you want to do is search (filter) those 16 tables.
You could use a union all to do this in a single query:
select xxx, 'table1' as source_table
from table1
where id = ?
union all
select xxx, 'table2' as source_table
from table2
where id = ?
and so on. The second derived field source_table can be used to determine which table returned which result.
You have to list all fields using aliases for fields with same name, and prefix with table names.
For example :
query = "SELECT table1.id as id_1, table2.id as id_2, ... WHERE id_1 = 23"
Probably a very long query to write, but you have solution to generate and paste it : You can do this for example with FlySpeed SqlQuery (free for personal use)
FlySpeed SqlQuery will generate all aliases for you, and automatically prefix with table names.
A little clarification would help. If all 16 tables have the same fields and you want them in a continuous list, you can use UNION as suggested above. On the other hand, if there are only a few fields that match and you want to compare the values for each table side-by-side, you'll want to use joins and provide aliases with the table names, as also suggested above.
However, looking at the snippet of code you've provided, I'm going to guess that you're either building some kind of stored procedure or else implementing SQL in some other language. If that's the case, how about loading your table names into an array and using a for loop to build the query, such as the following psuedo-code:
tableList = ["table1", "table2"...]
fieldnames = ["field1", "field2"...]
query = "SELECT "
for i = 0 to count(tableList):
for j = 0 to count(fieldnames):
query = query + tablelist[i] + "." + fieldnames[j] + ", "
j++
i++
query = query + "FROM "
for i = 0 to count(tableList):
query = query + tableList[i] + ", "
i++
query = query + "WHERE " ...
And so forth. Much of this depends on what exactly you're looking to do, how often you're looking to do it, and how often the variables (like which tables or fields you're using) are going to change.

jpql left join fetch not returning results for like

In a spring mvc app using hibernate and MySQL, I have written the following query method to return a list of names with patients:
#SuppressWarnings("unchecked")
public Collection<Person> findPersonByLastName(String ln) throws DataAccessException{
Query query = this.em.createQuery("SELECT DISTINCT pers FROM rimPerson pers left join fetch pers.names nm WHERE nm.family LIKE :lnm");
query.setParameter("lnm", ln);
return query.getResultList();
}
This is producing the following hibernate sql:
Hibernate:
select distinct
person0_.hppid as hppid1_340_0_,
names1_.HJID as HJID1_89_1_,
person0_2_.classCode_HJID as classCod2_339_0_,
person0_1_.administrativeGenderCode_HJID as administ2_341_0_,
person0_1_.birthTime_HJID as birthTim3_341_0_,
names1_.DELIMITER_ as DELIMITE2_89_1_,
names1_.FAMILY as FAMILY3_89_1_,
names1_.named_entity_hppid as named5_89_1_,
names1_.SUFFIX as SUFFIX4_89_1_,
names1_.name_entity_HJID as name9_340_0__,
names1_.HJID as HJID1_89_0__
from
rim_person person0_ inner join rim_living_subject person0_1_ on person0_.hppid=person0_1_.hppid
inner join rim_entity person0_2_ on person0_.hppid=person0_2_.hppid
inner join rim_infrastructure_root person0_3_ on person0_.hppid=person0_3_.hppid
left outer join EN names1_ on person0_.hppid=names1_.name_entity_HJID
where names1_.FAMILY like ?
When I call the above jpql method with the following command, it returns zero results:
this.myappService.findPersonByLastName("");
I also get zero results when I cut and past the above generated hibernate code into the MySQL command line client and replace ? with ''.
If, however, I remove the where names1_.FAMILY like ? from the hibernate generated sql above and place the shortened sql into the MySQL command line client, I get four results, eachof which has a value for the lastname field.
How can I change the jpql so that it generates a hibernate query that returns the four results when `` is passed as the empty string parameter? I want the result set to include every result when the user gives empty input, but to give filtered results when the user types in any given text input.
The typical reason that like fails to do what you think it ought to do is to forget to put a wildcard in the pattern string. For example, if you want to match all user names that begin with 'Code' you must do something like name like 'Code%', NOT name like 'Code'. You can control exactly what your predicate matches with careful placement of %s in your string.
Try this to see all entities no matter what the value in family:
this.myappService.findPersonByLastName("%");
It is kinda cheesy to have the caller of findPersionByLastName have to put in the % wildcard. A better implementation is to have the caller specify which last name they are looking for, and then have the code that constructs the query put the wildcard in the right place. When you are looking for last names, you might do something like this:
query.setParameter("lnm", "%" + ln);
That would match anything that ends with the parameter that is passed to the method.

SQL rawQuery if contains

A quick question, I can't find it on the internet, probably I am looking at the wrong "term".
But how do you make a SQL query statement with "if contains"
"SELECT something FROM " + TABLE_NAME + " WHERE name **contains** '*String*'", null);
I know you got these statements: = > < >= <= but what to use for if contains?
You want the LIKE keyword
Depending on the variety of SQL for the wildcard.
...Where name like '%string%'
SQLite uses % for a sequence of 0 or more unspecified characters (like a *), and an underscore _ for any single character
SELECT something FROM table WHERE name LIKE '%spam%'
(percent signs act like asterisks in a "conventional" search, give or take.)
You can get much more complicated with dbms specific functions (eg, here's Oracle's) that can, situationally, add regular expressions and other ways of searching.
As always, watch out for collation issues and case.
you can use LIKE
"SELECT something FROM " + TABLE_NAME + " WHERE name like '%yourstring%'";
refer to: http://www.sqlite.org/lang_expr.html
Instead of "if contains" you can use the "like" statement...
the query will be...
"SELECT something FROM tablename where name like %'string'%"
This will return what u want,,,
For Example:
Your table name "abc" contains Jarry,Jack,John,Josh,.....
if u run the query
select * from abc where name like %Ja%
it will return
Jarry,Jack..

Hibernate Detached Criteria

I have a DetachedCriteria which I am using to search a table based on a name field. I want to make the search case-insensitive, and am wondering if there is a way to do this without using HQL. Something like:
private void searchByFullName(DetachedCriteria criteria, String searchCriteria) {
criteria.add(Restrictions.like("fullName", "%" + searchCriteria.toUpperCase() + "%"));
criteria.addOrder(Order.asc("fullName"));
}
But I want to make sure that it will ignore the case when it does the search, so the SQL it generates should look something like:
SELECT * FROM PEOPLE WHERE ? LIKE toUpper(FULL_NAME);
there is ilike
http://www.hibernate.org/hib_docs/v3/api/org/hibernate/criterion/Restrictions.html#ilike(java.lang.String,%20java.lang.Object)

Categories