How do you find a groupwise maximum, or the row containing the maximum value, in Doctrine? In SQL, I would typically do this using a self join as described here.
While it's possible to set up a self relation in Doctrine, are there any better ways to do this?
Example of groupwise max:
$query = Doctrine_Query::create()
->select("txs.id, txs.amount, txs.valid_from")
->from("Tx txs")
->where("txs.amount = (SELECT MAX(transact.amount) FROM tx transact WHERE txs.id = transact.id)");
Example of row containing maximum:
$query = Doctrine_Query::create()
->select("txs.id, txs.amount, txs.valid_from")
->from("Tx txs")
->where("txs.id = (SELECT transact.id FROM tx transact WHERE transact.amount = (SELECT MAX(transactx.amount) FROM tx transactx))");
These are probably not the only ways (or most clean), but I just tested both and they work.
This question is really old but it ranks highly on Google for "doctrine groupwise max" so I thought I'd add my solution.
In my case I had a parent Entity with many children and I wanted to select fields from the child with the highest ID.
$qb
->select('child1.field')
->from(Entity::class, 'entity')
->join('entity.children', 'child1')
->leftJoin('entity.children', 'child2', 'WITH', 'child1.entity=child2.entity AND child1.id<child2.id')
->where('child2.id IS NULL')
;
Related
I have this query
$installments = Installment::where('merchant_id',1)->with('bills')->get(); .
and I need to get sum() of bill_amount column where exists in bills tables .
I have tried this in controller:
$paid_amount = 0;
$not_paid_amount = 0 ;
foreach ($installments as $installment) {
$paid_amount += $installment->bills->where('status',1)->sum('bill_amount');
$not_paid_amount += $installment->bills->where('status',0)->sum('bill_amount');
}
this work but I think it's not best practices,
What is the best way to do that?
thanks in advance
I think you can better have a view in DB combining the two tables and does the summation and then select from the view.
you create in DB something like :(needs to be tweaked as per ur tables)
CREATE or replace VIEW `merchatnt_bills` AS select sum(`bill`.`bill_amount`),`mr`.`merchant_id` AS `merchant_id`
from ((`merchant` `mr`, `bills` `bill`) join `farms` `f`) where ((<put one to many relatuion between two tables>) and (<any other condition u like>)
group by <columns>)
I made this request for get all brands and all items of theses brand with leftJoin :
$brands = Doctrine_Query::create()
->from('Brand b')
->leftJoin('b.Item i')
->fetchArray();
But I want to get only 10 items of each brand, how can I put the limit on Item leftJoin ?
You have to use subquery like this:
->leftJoin('b.Item i WITH i.id IN (SELECT i2.id FROM Item i2 WHERE i2.brand_id=b.id LIMIT 10)')
I didn't test this but it should work.
I know it's late but this actually scored nr 1 on my google search and is unanswered:
Limiting a doctrine query with a fetch-joined collection? suggests using Paginaror object
Here is an example:
My code has Sources that contain rss links and Articles that are articles from the rss feed. So in this example I'll get one Source and all it's articles.
// get the articles (latest first) from source 743
$q=$this->getDoctrine()->getManager()
->createQuery('select s, a from MyCompanyRssBundle:Source s
join s.Articles a
where s.id = :id
order by a.id desc')
->setParameter('id',743);
$q->setMaxResults(1); // this limits Articles to be only 1
// when using $q->getResult();
$sources=new Paginator($q, $fetchJoin = true);
$sources=$sources->getIterator();
// $sources=$q->getResult();
var_dump($sources[0]->getArticles());
So I have a list(table) of about 100k items and I want to retrieve all values that match a given list.
I have something like this.
the Table Sections key is NOT a primary key, so I'm expecting each value in listOfKeys to return a few rows.
List<int> listOfKeys = new List<int>(){1,3,44};
var allSections = Sections.Where(s => listOfKeys.Contains(s.id));
I don't know if it makes a difference but generally listOfKeys will only have between 1 to 3 items.
I'm using the Entity Framework.
So my question is, is this the best / fastest way to include a list in a linq expression?
I'm assuming that it isn't better to use another .NETICollection data object. Should I be using a Union or something?
Thanks
Suppose the listOfKeys will contain only small about of items and it's local list (not from database), like <50, then it's OK. The query generated will be basically WHERE id in (...) or WHERE id = ... OR id = ... ... and that's OK for database engine to handle it.
A Join would probably be more efficient:
var allSections =
from s in Sections
join k in listOfKeys on s.id equals k
select s;
Or, if you prefer the extension method syntax:
var allSections = Sections.Join(listOfKeys, s => s.id, k => k, (s, k) => s);
I'm new to Doctrine but somewhat familiar with SQL. I have a very simple schema with Users and Challenges. Each Challenge has a "challenger id" and a "opponent id" which are foreign keys into the User table. I want to print a list of all challenges, with the output being the names from the User table. Here is my Doctrine query;
$q = Doctrine_Query::create()
->select('u1.name challenger, u2.name opponent')
->from('Challenge c')
->leftJoin('c.Challenger u1')
->leftJoin('c.Opponent u2');
The problem is that this only returns one row. I've used the getSqlQuery() command to look at the generated SQL which ends up being:
SELECT u.name AS u__0, u2.name AS u2__1 FROM challenge c
LEFT JOIN user u ON c.challenger_id = u.id
LEFT JOIN user u2 ON c.opponent_id = u2.id
When run in a 3rd party SQL client this query retrieves all of the rows as expected. Any idea how I can get all of the rows from Doctrine? I'm using $q->execute() which I understand should work for multiple rows.
Thanks.
For me it worked by chaning the hydration mode:
$result = $query->execute(array(), Doctrine_Core::HYDRATE_SCALAR);
Set result set then returns an array instead of objects.
I just ran into this issue and in my case the problem was that my query didn't select any field from the FROM table. Example:
$query = Doctrine_Query::create()
->select(
'ghl.id as id,
ghl.patbase_id as patbase_id,
ghl.publication_no as publication_no,
ghl.priority_no as priority_no
'
)
->from('GridHitListContents ghlc')
->leftJoin('ghlc.GridHitList ghl')
As you can see there is no selected field from the GridHitListContents table.
with a $query->count() I got 2000ish results, but with $query->fetchArray() only the first one.
When I added
$query = Doctrine_Query::create()
->select(
'ghlc.id,
ghl.id as id,
...
'
)
->from('GridHitListContents ghlc')
->leftJoin('ghlc.GridHitList ghl')
I got back all my results.
$query->fetchOne() work fine for me.
Use this $result = $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY)
I'm trying to get Entity Framework to select an object and filter its collection at the same time. I have a JobSeries object which has a collection of jobs, what I need to do is select a jobseries by ID and filter all the jobs by SendDate but I can't believe how difficult this simple query is!
This is the basic query which works:
var q = from c in KnowledgeStoreEntities.JobSeries
.Include("Jobs.Company")
.Include("Jobs.Status")
.Include("Category")
.Include("Category1")
where c.Id == jobSeriesId
select c;
Any help would be appreciated, I've been trying to find something in google and what I want to do is here:http://blogs.msdn.com/bethmassi/archive/2009/07/16/filtering-entity-framework-collections-in-master-detail-forms.aspx
It's in VB.NET though and I couldn't convert it to C#.
EDIT: I've tried this now and it doesn't work!:
var q = from c in KnowledgeStoreEntities.JobSeries
.Include("Jobs")
.Include("Jobs.Company")
.Include("Jobs.Status")
.Include("Category")
.Include("Category1")
where (c.Id == jobSeriesId & c.Jobs.Any(J => J.ArtworkId == "13"))
select c;
Thanks
Dan
Include can introduce performance problems. Lazy loading is guaranteed to introduce performance problems. Projection is cheap and easy:
var q = from c in KnowledgeStoreEntities.JobSeries
where c.Id == jobSeriesId
select new
{
SeriesName = c.Name,
Jobs = from j in c.Jobs
where j.SendDate == sendDate
select new
{
Name = j.Name
}
CategoryName = c.Category.Name
};
Obviously, I'm guessing at the names. But note:
Filtering works.
SQL is much simpler.
No untyped strings anywhere.
You always get the data you need, without having to specify it in two places (Include and elsewhere).
No bandwith penalties for retrieving columns you don't need.
Free performance boost in EF 4.
The key is to think in LINQ, rather than in SQL or in materializing entire entities for no good reason as you would with older ORMs.
I've long given up on .Include() and implemented Lazy loading for Entity Framework