I need to create a query in NHibernate that would search for a product of two columns, like this:
WHERE a*b = param1
leaving efficiency aside (assume I have little rows or actual query will have extra conditions that will exploit some indexes) how do I do it in NHibernate? Preferably the solution should work with DetachedCriteria. I know I could use native SQL with Expression.Sql() but is there any other, better, way? Can I do this in HQL?
You can do this with HQL or Expression.Sql as you mentioned. HQL supports many different SQL expressions; see this section.
For example:
session.CreateQuery("from test t where t.a * t.b = 4").List();
Related
I am working on a application where I need to query(simple as well as complex) on a database many times.
I can understand that for simple queries there won't be a substantial difference between any of the approach mentioned above.
I would like know the efficient way in case of semi complex and complex queries.
Suppose I have a Domain class say
Class Sample{
String firstName
String lastName
long timeStamp
}
Now, I want to get the latest two records.So either I can write an
SQL query
select first_name, last_name from sample order by time_stamp desc limit 2;
HQL query
String queryString = "select firstName, lastName from Sample order by timeStamp desc"
List sampleList = Sample.executeQuery(queryString, [max: 2, offset: 0])
GORM query
def list = Sample.list(max: 2, sort: "timeStamp", order: "desc")
Out of this which will be the efficient way to query a database?
There is no significant difference between these 3. If you turn on query logging you should see that the SQL is virtually the same in all 3 cases.
However, if using HQL or GORM you can cache the results of the query. This might lead to greater efficiency if the query frequently returns the same results. On the other hand if the query rarely returns the same results (e.g. because the sample table is frequently updated), enabling query caching may reduce efficiency.
Ultimately, worrying about performance at this level is likely a case of premature optimization. I'd advise doing the simplest thing, which is probably GORM in this case, and worry about performance only when a performance problem has been identified.
The fastest and most performant way would be to use dialect-specific SQL queries and no ORM at all.
In GORM/Hibernate there's no substantial differences between those ways, what is more important is the code readability. In this case the criteria queries win over SQL/HQL counterparts, unless findAllBy* can be applied.
As injecteer mentioned before, the native SQL query is always the most efficient way to get the requested results.
All other approaches depend the implementation of the GORM-Datastore resp. the Query-mapping implementation. Both (the HQL and the critera) queries need to be translated to a native SQL-dialect (if using a SQL-Database) before the query is send to the database. In the given example both queries will result in the same native-SQL statement.
I'm using QueryOver<> to execute a series of subqueries using a conjunction. Here is some psuedo code that explains what I'm doing:
Conjunction conj = new Conjunction();
conj.Add(Subqueries.WhereProperty<Customer>(...).In(QueryOver.Of<Foo>().Where(...));
conj.Add(Subqueries.WhereProperty<Customer>(...).In(QueryOver.Of<Bar>().Where(...));
var result = session.QueryOver<Customer>()
.Where(conj)
.List();
This works fine but I've come across a scenario where I need to use HQL (CreateQuery()) for one of my subqueries. The reason I need to use HQL is because I need a theta (aka cross) join due to an unmapped relationship (unfortunately I can't change this).
Is there a way I can use CreateQuery() (or CreateCriteria() assuming I can do theta joins) to define subqueries and specify the top level query using QueryOver<>()?
No, HQL queries and QueryOver / Criteria queries cannot be combined.
You can use plain SQL in QueryOver / Criteria.
Basically here's the prob:
I can't change existing queries with "(+)" joins
I need to use Hibernate.
I can't put an association between these independent tables.
What I got so far is to use
entityMgr.createNativeQuery("my join (+) query here");
I then store it in a generic
List<Object> list = query.getResultList()
And get column values via
for(Object obj: list) {
firstColVal = obj[1]
...
}
Question: Is this the best option I've got? Are there better solutions?
Edit: You guys can suggest a more fitting ORM framework than Hibernate :)
The oracle join operation that you can not remove from your query is deprecated as it was introduced before ANSI standard.
That operator is different from typical join, but the main difference is that you can do less with it then with ANSI notation.
A solution for you might be to create a view on database that will be mapped in code. But your solution is still valid. You can additionally add a result transformer, that will produce valid tuple for result.
There are 2 queries:
select a,b,c,d from test where a=1 or a=2 or a=3
and
select a,b,c,d from test where a in (1,2,3)
Which one performs better? In the table there is an index on column a.
this should depend.
as you said in your comment, there are many variables.
the best way is to run some kind of explain plan for each specific query and see the difference (if there is any) on the specific database with the specific data loaded and the specific query.
stylistically, which is not the question, I personally prefer the IN clause in these cases.
Most - if not all - query optimizers will rewrite one form to the other before choosing an execution plan. So these two will have the same performance.
Generally NO! The OR operator is more flexible and can be used to evaluate many more conditions than the IN operator.
While it's true that any condition using IN operator ( inclusions ) can be replaced with an equivalent one using OR operator, it isn't true the other way: there is a really big number of conditions involving the OR operator that don't have equivalent condition using the IN operator.
This means that inclusions can be better identified when using their proper operator ( IN ), instead of a more general purpose one, so that they can be efficiently elaborated.
I have an SQL script (currently running against SQLite, but it should probably work against any DB engine) that uses the same subquery twice, and since it might be fetching a lot of records (the table has a couple of million rows) I'd like to only call it once.
A shortened pseudo-version of the query looks like this:
SELECT * FROM
([the subquery, returns a column of ids]) AS sq
[a couple of joins, that fetches things from other tables based on the ids]
WHERE thisorthat NOT IN ([the subquery again])
I tried just using the name (sq) in various ways (with/without parenthesis, with/without naming the column of sq etc) but to no avail.
Do I really have to repeat this subquery?
Clarification:
I am doing this in python and sqlite as a small demo of what can be done, but I would like my solution to scale as well as possible with as little modification as possible. In the real situation, the database will have a couple of million rows, but in my example there is just 10 rows with dummy data. Thus, code that would be well optimized on for example MySQL is absolutely good enough - it doesn't have to be optimized specifically for SQLite. But as I said, the less modification needed, the better.
There is a WITH clause in standard SQL, however, I don't know if it is supported by SQLlite - though of course worth a try:
WITH mySubQuery AS
(
[the subquery code]
)
SELECT * FROM
mySubQuery AS sq
[a couple of joins, that fetches things from other tables based on the ids]
WHERE thisorthat NOT IN (mySubQuery)
That said, what you do here will likely be horribly slow for any data set that is more than a few thousand rows, so I'd try to remodel it if possible - NOT IN should be avoided in general, especially if you also have a couple of joins.
Do you need a subquery? You could probably rewrite using an OUTER JOIN e.g. something like:
SELECT *
FROM [the subquery's FROM clause] AS sq
RIGHT OUTER JOIN [a couple of tables based on the ids]
ON thisorthat = sq.[a column of ids]
WHERE sq.[a column of ids] IS NULL;
In general, I question the need to eliminate the duplication. The SQL compiler can see that two subqueries are identical and chose to only do them once if that seems optimal.
In addition, by leaving duplicates in the source, the SQL compiler and optimizer is given the opportunity to treat them differently. For example the subquery flattening optimization of SQLite might be applied to one of a pair of duplicates or applied differently to each. See section 9.0, Subquery flattening of https://www.sqlite.org/optoverview.html.
you can put the SELECT part into a View than you can filter the View results using the alias "sq"
I hope it's helpful