I'm building a small program in Java Hibernate handling a subpart of the DBLP database (parsed from XML into a SQL db).
I've queries manipulating big chuncks of data so I want to limit the output result to 10 so it goes faster.
Query query = this.session.createQuery("select A.author_id "
+ "from publication as P "
+ "join P.authors as A "
+ "where P.year <= 2010 and P.year >= 2008 "
+ "group by A.author_id "
+ "having count(distinct P.year) = 3");
query.setMaxResults(10);
this.authors = query.iterate();
That piece of code is supposed to retrieve all the authors who published at least once every year between 2008 and 2010 included.
My problem is that the line "query.setMaxResults(10);" simply does not have effect, the SQL command generated by Hibernate is
select author2_.Author_id as col_0_0_ from publication publicatio0_ inner join author_publication authors1_ on publicatio0_.Publication_ID=authors1_.publication_id inner join author author2_ on authors1_.author_id=author2_.Author_id where publicatio0_.Year<=2010 and publicatio0_.Year>=2008 group by author2_.Author_id having count(distinct publicatio0_.Year)=3
limit ?
Remarque the "limit ?" at the end.
So my question is simple, how do I use properly setMaxResults to get a correct SQL Limit ?
EDIT: all the limit stuff works fine, I misunderstood the use of limit in SQL, what I'm looking for is a way to stop the execution of the query after a given number of rows corresponding to the conditions is found, so that it does not take days to get thousands useless rows but simply returns the 10 first found rows for example.
Thanks in advance !
Related
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.
I need delete from table on operation of same table .JPA query is
DELETE FROM com.model.ElectricityLedgerEntity a
Where a.elLedgerid IN
(SELECT P.elLedgerid FROM
(SELECT MAX(b.elLedgerid)
FROM com.model.ElectricityLedgerEntity b
WHERE b.accountId='24' and b.ledgerType='Electricity Ledger' and b.postType='ARREARS') P );
I got this error:
with root cause org.hibernate.hql.ast.QuerySyntaxException: unexpected
token: ( near line 1, column 109 [DELETE FROM
com.bcits.bfm.model.ElectricityLedgerEntity a Where a.elLedgerid IN (
SELECT P.elLedgerid FROM ( SELECT MAX(b.elLedgerid) FROM
com.bcits.ElectricityLedgerEntity b WHERE b.accountId='24'
and b.ledgerType='Electricity Ledger' and b.postType='ARREARS') P ) ]
at
org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:54)
at
org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:47)
at
org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:82)
at
org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:284)
Same query is running on mysql terminal ,but this is not working with jpa .Can any one tell me how i can write this query using jpa .
I don't understand why do you use Pbefore the last parenthesis...
The following code is not enough ?
DELETE FROM com.model.ElectricityLedgerEntity a
Where a.elLedgerid IN
(SELECT MAX(b.elLedgerid)
FROM com.model.ElectricityLedgerEntity b
WHERE b.accountId='24' and b.ledgerType='Electricity Ledger' and
b.postType='ARREARS')
Edit for bypassing mysql subquery limitations :
The new error java.sql.SQLException: You can't specify target table 'LEDGER' for update in FROM clause
is known in mysql when you use it with JPA. It's one MySQL limitation.
A recent stackoverflow question about it
In brief, you cannot "directly" updated/deleted a table that you query in a select clause
Now I understand why your original query did multiple subqueries seemingly not necessary (while it was useful for mysql) and had a "special" syntax.
I don't know tricks to solve this problem in JPA (I don't use the MySQL DBMS for a long time now).
At your place, I would do two queries. The first where you select the expected max elLedgerid and the second where you could delete line(s) with the id retrieved in the previous query.
You should not have performance issues if your sql model is well designed, the sql indexes well placed and the time to access to the database is correct.
You cannot do this in a single query with Hibernate. If you want to delete the max row(s) with Hibernate you will have to do so in two steps. First, you can find the max entry, then you can delete using that value in the WHERE clause.
But the query you wrote should actually run as a raw MySQL query. So why don't you try executing that query as a raw query:
String sql = "DELETE FROM com.model.ElectricityLedgerEntity a " +
"WHERE a.elLedgerid IN (SELECT P.elLedgerid FROM " +
"(SELECT MAX(b.elLedgerid) FROM com.model.ElectricityLedgerEntity b " +
"WHERE b.accountId = :account_id AND b.ledgerType = :ledger_type AND " +
" b.postType = :post_type) P );";
Query query = session.createSQLQuery(sql);
query.setParameter("account_id", "24");
query.setParameter("ledger_type", "Electricity Ledger");
query.setParameter("post_type", "ARREARS");
Just want to extend existing answer:
In brief, you cannot "directly" updated/deleted a table that you query in a select clause
This was lifted with starting from MariaDB 10.3.1:
Same Source and Target Table
Until MariaDB 10.3.1, deleting from a table with the same source and target was not possible. From MariaDB 10.3.1, this is now possible. For example:
DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);
I am trying to execute an SQL query into Hibernate because of the complexity of it. To do so, I am using the following method:
session.createSQLQuery(sSql).list();
And the SQL query is:
String sSql = "select timestamp, value, space_name, dp_id, dp_description from "+sTable+
" inner join space_datapoint on id = dp_id and timestamp between "+
" (select max(timestamp)-30 day from "+sTable+") and (select max(timestamp) day from "+sTable+")"+
" order by space_name";
The SQL query tries to retrieve a set of values by means of cross references between multiple table/views. The result is a list of objects (different fields from the tables). I have tested the query in the SQL manager of the database and it works. However, when I run it inside the Hibernate framework, it takes a lot of time (I had to stopped the debugger after some minutes, whereas it should take over 5 seconds according to the tests). Do you know what could be the mistake? Or a possible solution?
Thanks a lot in advance,
My database table(geo ip lookup) is having 7 columns,of which 2 columns constitute < composite-id>.
Now when i lookup for a value using first 2 coloumns it takes me 12-14 seconds to fetch a record..
My DAO code looks like this:
String queryString = "from Igeo igeo where igeo.ip_from <= " + ip
+ "and igeo.ip_to >= " + ip;
Query q = session.createQuery(queryString);
List<Igeo> igeoList = q.list();
if(igeoList.size() > 0){
Igeo igeo = igeoList.get(0);
ISP = igeo.getIsp();
...
...
}
*Igeo = class in java represnting table
**Record is fetched when ip lies between values of composite-id columns eg.
ip_from = 1 ; ip_to = 3 ; ip = 2;
so above row will be returned
This table is only used to read records ,please suggest me a queryString which is more efficient than above
First remove hibernate and run your query in a query browser and see how long it takes to return. If it takes the same amount of time it's not Hibernate. It's the performance of the database. Make sure you add indexes onto the two columns ip_from and ip_to. You can also execute a query plan on your query to see what the database is running under the hood and try and optimize the query plan.
I would suggest NOT using concatenation onto your query as you are. That produces a security hole allowing potential SQL injection from outside parties. It's better to use the following:
Query q = session.createQuery("from Igeo igeo where igeo.from_ip >= ? and igeo.to_ip <= ?");
q.setString( 0, ip );
q.setString( 1, ip );
You could also used named parameters which might shorten it up a bit more.
If the table IGeo does not contain overlapping ranges of ip_from and ip_to, you might try this
String queryString = "FROM Igeo igeo"
+ " WHERE igeo.ip_to >= " + ip
+ " ORDER BY igeo.ip_to";
Then check the first item in the list (to see that ip_from <= ip).
Even if the table could contain overlapping ranges of ip_from, ip_to, I bet the above HQL will run faster.
<Aside> You really should not concatenate a raw string like "ip" into HQL or SQL. It leads to SQL Injection Attack vulnerabilities. Use a query parameter instead</Aside>
Also, verify that your database has an index on the column corresponding to Igeo.ip_to.
Sounds to me from your description, that the database has a primary key of Igeo.ip_from + IGeo.ip_to. If the values of ip_from and ip_to are not overlapping, that does not seem to be normalized. You should need only a single column for the primary key. If you have chosen to use both columns as a primary key, the above query will benefit by adding a single index.
Some databases will perform better if you add an index containing all the columns in the table, starting with ip_to and ip_from. (This enables the database to satisfy the query by accessing only the index). Not sure if MySQL can optimize to this extent, but I know DB2 and Oracle will provide this.
Major Update after a couple days of debugging:
I run a few queries similar to :
SELECT RTRIM(part) as part
FROM tableP pm
LEFT join tableS s on pm.id = s.id
INNER JOIN tableC cm ON cm.id = pm.id
WHERE name = 'NGW' AND status NOT IN ('NL', 'Z')
GROUP BY RTRIM(part), isnull(s.value,0)
ORDER BY isnull(s.value,0)
It is run in Java like so:
PreparedStatement select = con.prepareStatement(
"SELECT RTRIM(part) as part" +
"FROM tableP pm " +
"LEFT JOIN tableS s ON pm.id= s.id " +
"INNER JOIN tableC cm ON cm.id= pm.id " +
"WHERE name =? AND status NOT IN ('NL', 'Z') " +
"GROUP BY RTRIM(part), isnull(s.value,0) " +
"ORDER BY isnull(s.value,0) " );
select.setString(1, name);
ResultSet rs = select.executeQuery();
while(rs.next()){
... Data is Loaded...
The queries have been running fine inside of a Java application. Suddenly 3 or 4 queries of this form went from taking less then a second to over a minute.
I have copied the exact query from SQL Profiler and when run directly on the database it preforms in less then a second. I started to make changes to the query and found any change to the query would return it to 1 second performance even adding a single space between a statement. But as soon as I returned it to its original exact state it would take 60+ seconds.
Core Question:
So, I have a fix, but what could cause a query to run differently even with just a change as small as whitespace?
Is it possible that the execution plan is corrupted? Can you try explicitly clearing the plan cache?
http://msdn.microsoft.com/en-us/library/aa175244(v=sql.80).aspx