I'm working on a feature which allow some users to define their own SQL queries and run them on the database.
Basically a query could look like this:
1. SELECT first_name, last_name FROM user;
2. SELECT first_name, last_name, id, address, email FROM user.
As you can see there may be a different number of columns in the result table.
Is there a way to handle this in Hibernate?
For instance, the basic usage displayed below does not help me in any way because I cannot be sure that each result row has at least 2 columns.
Query query = session.getSession().createSQLQuery(queryStr);
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
while (results.next()) {
data.put("firstName", String.valueOf(results.get(0)));
data.put("lastName", String.valueOf(results.get(1)));
}
Furthermore, I don't think I can use the select new map because the users have to run native MySQL queries.
Is there any solution to this?
Thanks in advance for your time and suggestions!
First of all, I do not think that it is a good idea to expose an interface that allows SQL input to users.
Anyway, in your case you could program the SQL result set extraction yourself. There is no need for object relational mapping, if you do not map into objects. You could then go and just check for the existence of the columns and map them right away into your data structure. Nice way to learn plain JDBC. Just for the case you use Hibernate for other issues in your application, you can even mix the approaches.
Related
Suppose I have a table with columns 'name', 'age', 'city', 'country'. I would like to expose the database query interface to users, that is, they should be able to perform all kinds of queries that sql let's us do.
The only way I can think of doing this is to have a row for each column where each row is of the form:
column name | operator | value
An example query in an activity would be:
name | = | Bob
age | > | 25
Then with that information I could have a method perform the query and return the result.
For this simple example it would work. But there are more interesting things one can ask sql and this approach would fail at a lot those queries.
What can I do about this?
First of all, you need to think what operations are you going to allow your users. The most common SQL queries are SELECT, INSERT, UPDATE, DELETE. Once you have the list of operations that you are going to provide, you need to think of the parameters that the user can select while making any of these queries. For example, if the user wants to fetch (SELECT) some data, what can he provide as input, in your case the age of the person. Similar case for the other queries.
So once you have the above information, you will need to convert it into a query. This can be done by creating a utility or helper class which takes into account the users query as well as parameters and forms the SQL query which you can execute on your database.
For example, lets take the StackOverflow Jobs page (https://stackoverflow.com/jobs?med=site-ui&ref=jobs-tab). Here you can see that the user can fetch data based on multiple parameters which are keyword, location, remote etc. Taking this example into consideration, your utility will create a SELECT query and pass the user selected parameters and generate a SQL query of the form
SELECT jobs WHERE is_remote=<user_param> AND tech=<user_param> AND compensation=<user_param>
This is just an overview of what needs to be done. There might be some changes based on your exact use case. But this will just about cover what you need to achieve.
I have a two tables: Person and House, the mapping is one to one.
Now I have to assign the address of Person and House (which can be different) to the same address.
There are more than 5000 records. Which will be faster? Using Code to update the entities one by one, e.g.
for (id : Ids) {
Person person = PersonDAO.find(id);
person.setAddress ("abc");
}
and then doing same with House;
Or should I use JPQL to update both in two different queries, e.g.
UPDATE Person p SET p.Address = "abc" WHERE ID IN(.....ID QUERY)
My question is what will be faster? Will the update using JPQL have the same performance, same as that in code? Or should I use native query to NOT load the entities, as I only want performance.
Using the query will be faster (and much more memory efficient), as the query provider will translate the JPQL query to native SQL. Also, if you use entities directly, the number of queries made against the database will be siginificantly higher (one select and update for each and every row).
The native query will be faster, as it doesn't have to translate anything.
If you want it to be even faster, you can use a PreparedStatement. With the .addBatch() method you add the query to the batch, and with the executeBatch() method you will execute the full batch, minimizing the amount of times being switched between user and kernel mode.
I have a following problem. In application, which I am developing, we use Hibernate and every query is written with Criteria API. Now, in some places, we want to add possibility for user to write some SQL code which will be used as part of where clause in a query. So basically, user can filter data displayed to him from database in his own way.
For a few days now, I am trying to find a way to modify our previous queries to acquire result described above. Here is what I know:
It looks like you cannot combine Criteria API with native SQL. You can either write whole query in SQL or use only criteria API. Is that right?
I am asking this question because it would be the easiest solution, just to use this SQL code as another predicate in where clause in our query. But I don't think it's possbile on this level.
I know on which table user wants to filter data. So I could just execute native SQL query and use result list as a parameter to IN clause in criteria query. But I don't know if it is efficient with many records in a result list.
So if I cannot do it on criteria API level, I thought that maybe I could somehow influence the SQL generetion process and put my SQL in a proper place but it seems to be impossible.
So my real question is: is it somehow possible to have access to SQL code of the query, after SQL generation phase but before actual execution of query? Just to manipulate with it manually? Can it be done safely and as far as possible simply?
Or maybe just try to parse this SQL written by user and use it in criteria query?
Changing existing criteria queries into native SQL queries is rather out of discussion.
Yes, you can get the SQL from the Hibernate criteria using the org.hibernate.loader.criteria.CriteriaQueryTranslator class.
This will allow you to append the additional SQL clause(s) to the end and execute it as a native SQL:
CriteriaQueryTranslator translator = new CriteriaQueryTranslator(factory, criteria, "myEntityName", CriteriaQueryTranslator.ROOT_SQL_ALIAS);
String select = translator.getSelect();
String whereClause = translator.getWhereCondition();
Personally though, if faced with this requirement I would shy away from accepting SQL from the end-user and give them a user interface to populate some type of filter object. This can then be converted into HQL criterion, which is much safer and doesn't tie your code as tightly to the database implementation.
Edit based on comments
Example of extracting SQL from a JPA query implemented with Hibernate:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<MyEntity> q = builder.createQuery(MyEntity.class);
Root<MyEntity> entity = q.from(MyEntity.class);
q.select(entity).orderBy(builder.desc(entity.get("lastModified")));
TypedQuery<MyEntity> query = entityManager.createQuery(q);
String sql = query.unwrap(org.hibernate.Query.class).getQueryString();
criteria.add(Restrictions.sqlRestriction(" AND ID in (1,2,3)" ));
Iam trying to implement memcache in my web application and just wanted to get suggestions that whether what iam doing is right in terms of design.
I have a class SimpleDataAccessor which run all my insert, update and select sql queries. So any query that has to be performed is executed inside the method of this class.
So inside the method where I have my select query implementation i have a method which stores the resultset in memcache like this.
storeinMC(resultset.getJSON(),sqlquery);
the sqlquery here is my key.
Also before running the selectquery i check in memcache that whether I have a resultset already for that query.
if((String res=getRSFromMC(sqlquery)==null)
So i've tried to keep it plain and simple.
Do you see any issues with this.?
As rai.skumar rightfully pointed out your SQL statements could be constructed differently (e.g. WHERE clause could contain same conditions in diff order, etc.)
So to overcome above mentioned issues, you need to parse your SQL and get all the relevant pieces from it. Then you can combine these pieces into a cache key.
You can take a look at SQL parsers: ZQL, JSqlParser, General SQL Parser for Java that return you java classes out of your SQL.
Another option would be to use JPA instead of straight JDBC. For example Hibernate has great JPA support and fully capable of caching your queries.
If you feel closer to JDBC you could use MyBatis that has very JDBC like syntax and caching support.
Consider below queries:
String k1 = "Select * from table"; //Query1
String k2 = "Select * from TABLE"; // Query2 ; notice TABLE is in caps
Both of above SQL queries are same and will fetch same data. But if above queries are used as keys in Memchached they will get stored at different places ( as k1.equals(k2) will return false).
Also if somehow you can ensure that there are no typos or extra spaces, it won't be very efficient as keys/queries could be very big.
i am migrating from ms access database to mysql database with java frontend so that my application can be used in linux as well .
in ms access here's what i would do
go to create query . write a select statement . call give the name of the query as query1.
when double clicking on query1 you would get the result of select statement in a tabular form.
next i would write a query2 which is also a select query. this query would be fetching data not from a table but query1 e.g select a,b from query1;
now i am on a mysql database using java
what would be the java statement for select a,b from query1 ?
what i mean to say is that i would connect to mysql using jdbc.
have query1 like this
string query1 = " select * from users " ;
then execute query using executeQuery(query1)
but i dont think i can do something like this.
string query2 = " select a,b from query1 " ;
and then executeQuery(query2)
so what is the way out ?
I ran into the exact same problems when I went from using MS Access to using a lot of SQL queries against a MySQL DB.
There are two ways I would approach this:
VIEWS:
Views are a great way to emulate a lot of the functionality you found in Access. One of the things I really liked about Access was the ability to separate my SQL into smaller queries and then re-use those queries in other queries. Views allow you to do essentially the same thing in that you define a query in a View and then you can write another query or View against that original View.
In my experience, however, Views tend to be really slow, especially when referencing calculated columns. With MySQL, I very rarely use Views (though perhaps others have found for efficient ways of implementing them).
SUBQUERIES (NESTED QUERIES)
As others have mentioned, subqueries are a great way to write multiple queries within one query. With a subquery, instead of putting the query name (as in Access) or View name (as explained above) within the SELECT portion of your code, you simply paste the entire SQL statement of the subquery.
You might write code like this to find only the 2009 sales and salesperson name for customers in a database:
SELECT
customer.Name,
customer.AccountNumber,
customer.SalespersonName,
ch.`2009 Sales`
FROM
customer
Left Join (
SELECT
customerhistory.AccountNumber,
SUM ( CASE WHEN customerhistory.`Year` = 2009
THEN customerhistory.`Sales`
ELSE 0
END
) AS `2009 Sales`
FROM
customerhistory
GROUP BY
customerhistory.AccountNumber
) ch ON customer.AccountNumber = ch.AccountNumber
In my work, I tend to use mostly subqueries since I find they run a lot faster than views, but your experience may vary.
You can do this all in MySQL. The query would look like
SELECT * FROM (
SELECT * FROM users
) query1;
You can either do nested queries (subqueries) like #muffinista suggested.
But i think you are looking for Views: http://dev.mysql.com/doc/refman/5.0/en/create-view.html.
In short, a view is a "pseudo table" that is a result of a query.
you can
create view q1 as
select * from table1 where f1>1
select * from q1 where f2<100
select * from table2 where user_id in (select user_id from users)