I have a Grails criteria that has associated children classes that are nullable. I need to get all results, even those with null children, but the criteria gets executed with an INNER JOIN. How do I get it to be executed with a LEFT JOIN?
Grails version is 1.3.7 (most recent), query is being executed via createCriteria().list
As question is old and lot of improvement has been done on this. Following will help someone searching like me.. Following works even with complex and{} and or{} blocks inside criteria query with collections. in eg. specialities is a collection.
List users = User.createCriteria().list(){
createAlias('specialities', 'sp', CriteriaSpecification.LEFT_JOIN)
ilike("sp.name","%"+trimPhrase+"%")
}
try to use a hql statement. for left joins see: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/queryhql.html
hql statements can be performed as follows: DomainClass.executeQuery("select from ....")
Related
I am trying to join a simple query with a very ugly query that resolves to a single line. They have a date and a userid in common but nothing else. Alone both queries work but for the life of me I cannot get them to work together. Can someone assist me in how I would do this?
Fixed it...when you union queries in hive it looks like you need to have an equal number of fields coming back from each.
Suppose I have a Parent model that has many Child, and that Child also belongs to OtherParent.
How can i find all Parent where ALL of its Child belongs to any OtherParent?
In pure SQL I could do
Parent.find_by_sql(<<SQL)
SELECT *
FROM parents p
WHERE NOT EXISTS (
SELECT *
FROM children
WHERE parent_id = p.id
AND other_parent_id IS NULL
)
SQL
(from here), but I'd prefer to do it by taking advantage of ActiveRecord if possible.
Thanks!
I'm using Rails 4.2.1 and PostgreSQL 9.3
Using arel can get you pretty far. The tricky part is how do you not write your entire query using arel's own query syntax?
Here's a trick: when building your query using where, if you use arel conditions, you get some extra methods for free. For instance, you can tail the subquery you have there with .exists.not, which will get you a (NOT ( EXISTS (subquery))) Toss that into parent's where-clause and you're set.
The question is, how do you reference the tables involved? You need Arel for that. You could use Arel's where with its ugly conditions like a.eq b. But why? Since it's an equality condition, you can use Rails' conditions instead! You can reference the table you're quering with a hash key, but for the other table (in the outer query) you can use its arel_table. Watch this:
parents = Parent.arel_table
Parent.where(
Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)
You can even reduce Arel usage by resorting to strings a little and relying on the fact that you can feed in subqueries as parameters to Rails' where. There is not much use to it, but it doesn't force you to dig into Arel's methods too much, so you can use that trick or other SQL operators that take a subquery (are there even any others?):
parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
Child.where(parent_id: parents[:id], other_parent_id: nil)
)
The two main points here are:
You can build subqueries just the same way you are used to building regular queries, referencing the outer query's table with Arel. It may not even be a real table, it may be an alias! Crazy stuff.
You can use subqueries as parameters for Rails' where method just fine.
Using the exceptional scuttle, you can translate arbitrary SQL into ruby (ActiveRecord and ARel queries)
From that tool, your query converts to
Parent.select(Arel.star).where(
Child.select(Arel.star).where(
Child.arel_table[:parent_id].eq(Parent.arel_table[:id]).and(Child.arel_table[:other_parent_id].eq(nil))
).ast
)
Splitting up the query-
Parent.select(Arel.star) will query for all columns in the Parent table.
Child.arel_table brings you into Arel-world, allowing you a little bit more power in generating your query from ruby. Specifically, Child.arel_table[:parent_id] gives you a handle onto an Arel::Attributes::Attribute that you can continue to use while building a query.
the .eq and .and methods do exactly what you would expect, letting you build a query of arbitrary depth and complexity.
Not necessarily "cleaner", but entirely within ruby, which is nice.
Given Parent and Child, and child is in a belongs_to relationship with OtherParent (Rails defaults assumed):
Parent.joins(:childs).where('other_parent_id = ?', other_parent_id)
I'm writing a Rails API on top of a legacy database with tons of tables. The search feature gives users the ability to query around 20 separate columns spread across 13 tables. I have a number of queries that check the params to see if they need to return results. They look like this:
results << Company.where('city LIKE ?', "#{params[:city]}").select('id') unless params[:city].blank?
and they work fine. However, I just added another query that looks like this:
results << Company.joins("JOIN Contact ON Contact.company_id = Company.id").where("Contact.first_name LIKE ?", "%#{params[:first_name]}%").select('company_id') unless params[:first_name].blank?
and suddenly my first set of queries started returning null, rather than the list of IDs they had been returning. The query with the join works perfectly well whether the other queries are functional or not. When I comment the join query out, the previous queries start working again. Is there some reason the query with a join would break other queries on the page?
I can't think of a particular reason why the join would be breaking your previous queries however I do have some suggestions for your query overall.
Assuming you've modelled these relationships correctly you shouldn't need to define the join manually. On another note, you're not querying against the company at all so you can use an includes instead of a join - this will allow you to access its data without firing another query.
If you wanted to access company data (ie. query.company.name) use an includes like so:
Contact.includes(:company).where('first_name LIKE ?', param).select(:company_id).distinct
However it appears all you really want is an array of ID's (which exists on the contact model), because of this you can lighten things up and not include the company at all.
Contact.where('first_name LIKE ?', param).select(:company_id).distinct
Whenever you get stuck never forget to checkout the great resources over at: http://api.rubyonrails.org/ - they are an absolute life saver sometimes!
It turned out that the queries with a join needed to be placed above the queries without a join. I'm not sure why it behaves this way, but hopefully this helps someone else down the line.
I want to fetch from my DB all requirements related to a given project(in this case currentProject)
I've just used two ways to do this
first one :
Requirement.withCriteria {....
eq("project", currentProject)
...
}
I note that this query doesn't use equals method of Project class, but this query returns me exactly what I want.
second
Requirement.withCriteria {
....
currentProject == property('Project')
...
}
This query use equals method to compare two projects, but I could not overwrite equals method that a exception has been thrown saying "grails can't cast hibernateBuild to domain"
So, I wonder know what the difference between those two queries ?
Thanks to all!
withCriteria method goes to the Database to fetch your entities.
On the database level there is no concept of equals (DB does not know anything about Java). First query gives you the right results because it compares the DB mapping (PRIMARY / FOREIGN keys).
As for the second query - I do not advice to use it. If it uses equals, when it fetches all projects from the DB into memory. And that is a really bad idea.
I am using Solr's (4.0.0-beta) join capability to query an index that has documents with parent/child relationships. The join query works great, but I only get the parent documents in the search results. I believe this is the expected behavior.
Is it possible, though, to get both the parent and the child documents to be returned in the search results? (as separate search hits).
For example:
Parents:
SolrDocument{uid=m_1, media_id=1}<br/>
SolrDocument{uid=m_2, media_id=2}<br/>
SolrDocument{uid=m_3, media_id=3}
Children:
SolrDocument(uid=p_1, page_id=1, fk_media_id=[1], partNumber=[abc, def, xyz]}<br/>
SolrDocument(uid=p_2, page_id=2, fk_media_id=[1,2], partNumber=[123, 456]}<br/>
SolrDocument(uid=p_3, page_id=3, fk_media_id=[1,3], partNumber=[100, 101]}
I query by partNumber like this:
{!join from=fk_media_id to=media_id}partNumber:abc
and I get the parent document (uid=m_1) in the results, as expected. But I would like, in this case, both the parent and the child to be returned in the results. Is that possible?
No, It´s not posible. According to Solr Wiki:
For people who are used to SQL, it's important to note that Joins in Solr are not really equivalent to SQL Joins because no information about the table being joined "from" is carried forward into the final result. A more appropriate SQL analogy would be an "inner query""
http://wiki.apache.org/solr/Join
You have to denormalize all your data to do that or run two different querys.