Paging in hibernate subqueries - sql

I have quite a complex query that applies different layers of filtering and requires ordering/paging.
In pseudo-SQL I want to do the following:
SELECT ... FROM a WHERE a.id in (SELECT a.id FROM a WHERE [...] limit 10,10)
I use Criteria and DetachedCriteria, something like this:
Criteria criteria = session.createCriteria(xx.class, "xx");
DetachedCriteria idFilterSubQuery = DetachedCriteria.forClass(xx.class, "xx");
//ADD ALL FILTERS TO idFilterSubQuery
//ADD ALL OUTER_JOINS TO criteria and idFilterSubQuery
criteria.add(Subqueries.propertyIn("id", idFilterSubQuery));
Now for the paging, I can't add it to criteria, since the outer-joins mess it up... So I need to add it to idFilterSubQuery... BUT, DetachedCriteria does not have setFirstResult() and setMaxResult()... But you can't add normal Criteria as SubQuery (I haven't found a way at least)...
I would like a solution that doesn't fetch all id's first, and the full objects afterwards (reduce a round-trip to the DB)
Any ideas how to achieve this? So either use Criteria as SubQuery or add paging to a DetachedCriteria...
I'm using Hibernate 4.2.21

Related

Filter by related document in RavenDB

How can I translate the following SQL query to RQL?
Select bike.* from Bike
inner join Appointment on Bike.BikeID = Appointment.BikeID and
Appointment.Status != 'Booked'
I know that in Mongo it is possible to filter by related documents.
However, RavenDB documentation says that:
It's important to remember that the load clause is not a join; it's applied after the query has already run and before we send the interim results to the projection for the final result. Thus, it can't be used to filter the results of the query by loading related documents and filtering on their properties.
So what is the correct way to run such a query in RavenDB?

Django ORM filter multiple fields using 'IN' statement

So I have the following model in Django:
class MemberLoyalty(models.Model):
date_time = models.DateField(primary_key=True)
member = models.ForeignKey(Member, models.DO_NOTHING)
loyalty_value = models.IntegerField()
My goal is to have all the tuples grouped by the member with the most recent date. There are many ways to do it, one of them is using a subquery that groups by the member with max date_time and filtering member_loyalty with its results. The working sql for this solution is as follows:
SELECT
*
FROM
member_loyalty
WHERE
(date_time , member_id) IN (SELECT
max(date_time), member_id
FROM
member_loyalty
GROUP BY member_id);
Another way to do this would be by joining with the subquery.
How could i translate this on a django query? I could not find a way to filter with two fields using IN, nor a way to join with a subquery using a specific ON statement.
I've tried:
cls.objects.values('member_id', 'loyalty_value').annotate(latest_date=Max('date_time'))
But it starts grouping by the loyalty_value.
Also tried building the subquery, but cant find how to join it or use it on a filter:
subquery = cls.objects.values('member_id').annotate(max_date=Max('date_time'))
Also, I am using Mysql so I can not make use of the .distinct('param') method.
This is a typical greatest-per-group query. Stack-overflow even has a tag for it.
I believe the most efficient way to do it with the recent versions of Django is via a window query. Something along the lines should do the trick.
MemberLoyalty.objects.all().annotate(my_max=Window(
expression=Max('date_time'),
partition_by=F('member')
)).filter(my_max=F('date_time'))
Update: This actually won't work, because Window annotations are not filterable. I think in order to filter on window annotation you need to wrap it inside a Subquery, but with Subquery you are actually not obligated to use a Window function, there is another way to do it, which is my next example.
If either MySQL or Django does not support window queries, then a Subquery comes into play.
MemberLoyalty.objects.filter(
date_time=Subquery(
(MemberLoyalty.objects
.filter(member=OuterRef('member'))
.values('member')
.annotate(max_date=Max('date_time'))
.values('max_date')[:1]
)
)
)
If event Subqueries are not available (pre Django 1.11) then this should also work:
MemberLoyalty.objects.annotate(
max_date=Max('member__memberloyalty_set__date_time')
).filter(max_date=F('date_time'))

C# NHibernate dynamically add Where clauses (jqgrid)

Is it possible to add where clauses dynamically to an NHibernate Query?
I have a collection of Clauses I need to Loop through and add a Where clause if required - i.e. if the user has entered multiple search criteria.
I Can write single queries, no problem, like this: get All Names beginning with 'a':
IEnumerable<Customer> customers = nHibernateSession.Query<Customer>().Where(x => x.Name.StartsWith("a")).ToList();
but I do not know how to then Add another where clause to this
Effectively I need something that is like this:
foreach (clauses in SelectionClauses)
{
//add a .Where(Clause) to The Session.Query
}
I suspect That The nHibernateSession.Query cannot be used this way...
Does anyone know How to do this?
You can do this with the Linq provider (session.Query) by doing something like:
var query = session.Query<MyClass>();
foreach(var clause in clauses)
query = query.Where(clause.BuildExpression());
Where BuildExpression returns Expression> for example
However this can get painful if you are using string name for your properties, and it will be a lot easier to achieve your result using session.QueryOver or session.CreateCriteria both of which support querying properties by their name instead of via expressions.

SQL: Handling multiple SELECT conditions?

I'm just an basic SQL user (mySQL+php now). I have search box with multiple input (conditions).
For example:
Color: ____
Size: ____
Price: ___
Condition: ___
Discount %: ___
Hit Count: ___
etc, many more ............
User may input 1 or more fileds.
Result should be filtered for multiple input also.
So, how can i handle this multiple conditions in Query?
I'm confusing how to write query (in former way):
SELECT * FROM _item_ WHERE color='silver' AND/OR .... ... ?????
????
A simple sample please.
The easiest approach would be to have a base query, that even without filter criteria, still returns results:
SELECT *
FROM _item_
WHERE 1=1
this then allows you to easily add additional criteria to further filter your results, based on what was specified in the user interface. So, if someone says they want to filter on the color "silver" and the condition "new", we just add these to the WHERE clause of our query:
SELECT *
FROM _item_
WHERE 1=1
AND color = 'silver'
AND condition = 'new'
each additional filter criteria can just be added with an AND to the end of the base query.
edit: as pointed out in other posts, this is a naïve approach and you need to be careful of SQL injection, but the original question asked for a simple example and this was as simple as I could think of.
There is no one simple solution. You could create dynamic SQL from scratch based on the parameters or you could use some a different SP for each combination of parameters or you could just get everything then filter in your client side or...
But be very careful about SQL injection.
I would suggest, before going any further, you read something like http://www.sommarskog.se/dyn-search.html and
http://www.sommarskog.se/dynamic_sql.html which give a lot of detail about this sort of thing. Long but worth it.
You can use COALESCE to dynamically construct the WHERE clause, if the supplied parameter is null then column value will be used instead so you just need to ensure that you pass null where appropriate:
SELECT * FROM Table
WHERE color = COALESCE(#Color,color)
AND condition = COALESCE(#Condition,condition)
Note that this assumes the use of a parameterised query so should be pretty SQL Injection proof.

Search - Order By Keywords

Is there any way to do something like this:
var keywords = SearchUtilities.FindKeyWords(q);
var j = (from p in _dataContext.Jobs
orderby p.JobKeywords.Select(jobKeyword => jobKeyword.Keyword)
.Intersect(keywords).Count())
.Take(10).AsEnumerable();
The main idea here is to order search results by the count of the keywords that exists both in the search query and in the keywords that associated with the jobs.
I don't want to bring all the records from the SQL-land first, and then orderby, because it's very slow. When I try that code it throws:
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.
Ideas?
If you are looking more performance on search, I suggest you to use Stored Procedure. In my opinion TSQL works faster than LinQ. because Linq gets all results, but Stored Procedure (TSql) doesn't take all records.