How to limit results of a left-join with Doctrine (DQL) - doctrine

In a symfony 2 application, I have 2 entities mapped by a oneToMany relation (user and rendezvous).
I'm trying to search into my user entity and join the last rendezvous for each user found.
The idea is something like that :
$qb = $this->createQueryBuilder('p');
$qb->select('p.id, p.last_name, p.first_name')
->leftJoin('p.rendezvous', 'i')
->select('i.date')
->where('i.user = p.user')
->orderBy('i.date', 'DESC')
->setFirstResult(0)
->setMaxResults(1)
->where('p.user IN ('.$users.')')
->orderBy('p.last_name', 'ASC')
->addOrderBy('p.first_name', 'ASC');
I should have results like :
1, Ben, Tooch, 2014-10-15 18:45:00
7, John, Snow, 2014-10-16 17:15:00
...
I tried to use the paginator function but without any success.
Thank you very much for your help.

As I add some more columns to get, I had to find another way to do it. I finally got a working DQL query :
$qb->select('p.id, p.last_name, p.first_name, r.date, r.othercolumn')
->leftJoin('p.rendezvous', 'r', 'WITH', 'p.id = r.user AND r.date = (SELECT MAX(r2.date) FROM \App\YourBundle\Entity\Rendezvous as r2 WHERE r2.user = p.id)')
->where('p.user IN ('.$users.')')
->orderBy('p.last_name', 'ASC')
->addOrderBy('p.first_name', 'ASC')
->groupBy('p.id');

try groupBy the entity you want to setMaxResults on.

Have you tried outputing the generated SQL and running it?
I'm not sure if you can use maxresults and firstResult in a left join like this, but if your idea is just to recover users and their last rendezvous, you could use max(i.date) and group by p.id, p.last_name, p.first_name.
But if you want to page it, simply join the two tables and order by i.date.
Hope it helps!

Related

Join on Eloquent breaks Relationships?

I have the following relation:
I have a many-to-many relation between Course and Users, and then again a has-many relation between Users and Certificates.
Now here is way how to get all users from one course, who have a certificate in the same course:
$user = $course->users()
->whereHas('certificates', function ($query) use($course){
$query->where('course_certificates.course_id', '=', $course->id);
})->first();
This will return a user with certificates $user->certificates.
This is the query.
SELECT *
FROM "course_users"
WHERE "course_users"."course_id" = ? AND
"course_users"."course_id" IS NOT NULL AND
EXISTS (
SELECT *
FROM "course_certificates"
WHERE "course_users"."id" = "course_certificates"."user_id" AND
"course_certificates"."course_id" = ?
)
If I use a join instead:
$user = $course->users()
->join('course_certificates', 'course_certificates.user_id', '=', 'course_users.id')
->where('course_certificates.course_id', '=', $course->id)
->first();
Then I get the same user, however the relationship $user->certificates is empty?
SELECT *
FROM "course_users"
INNER JOIN "course_certificates"
ON "course_certificates"."user_id" = "course_users"."id"
WHERE "course_users"."course_id" = ? AND
"course_users"."course_id" IS NOT NULL AND
"course_certificates"."course_id" = ?
Why is that?
I am not 100% sure, but if you use join I think laravel do not understand whatever table you are joining it with that it is a relation, it is just a join, it could mean anything, but the first query you are telling it what the relation means (whereHas some data for X relation).
Looking at the source code, I can confirm what I am saying: join and whereHas (and has).
getRelated() does the magic (adds the data to your relation). See that join does not do anything of this, it literally joins queries, nothing else related to relations. Also join comes from Query/Builder and any other method about relations comes from Eloquent/Builder.

how to convert query this query to laravel

SELECT *
FROM `digital_useraccess`
left join digital_publisher ON
access_publisher = pub_auto
left join digital_issue ON
issue_publisher = pub_auto
WHERE 1
without using laravel DB class method
Try this as reference
ModelName::where(conditions)
->leftjoin('digital_publisher','access_publisher','pub_auto')
->leftjoin('digital_issue','issue_publisher ','pub_auto')
->select('column_1','column_2',...)->get();
This might help :
::query()->where('<cplumn>' , '<operator>' ,
'<value>')->leftJoin('digital_publisher', 'access_publisher',
'=','pub_auto')->leftJoin('digital_issue', 'issue_publisher', '=',
'pub_auto')->select('<columns>')->get();/find();/first();

Laravel 5.6 Custom Query Build showing empty result

No errors, just an empty result. I am trying to work out why this query within a model is showing an empty collection.
Mysql Workbench query:
select
u.`name`, u.email, ual.admin, a.account_name
from
users as u
join users_account_link as ual on u.id = ual.user_id and u.account_id_in_use = ual.account_id
join accounts a on ual.account_id = a.id
where
u.sub = 'ABCDE';
Spits one row containing the desired result set.
Recreating this in Laravel query builder:
$settings = DB::table('users as u')
->join('users_account_link as ual', function ($join) {
$join->on('u.id', '=', 'ual.user_id')
->where('u.account_id_in_use', '=', 'ual.account_id');
})
->join('accounts as a', 'ual.account_id', '=', 'a.id')
->select('u.name as user_name', 'u.email as user_email', 'ual.admin as admin_check', 'a.account_name')
->where('u.sub',auth()->user()->sub)
->get();
dd($settings);
Provides an empty collection. I have done many custom queries which work well however the problem I have narrowed down the result set is the additional condition for join users_account_link as ual on u.id = ual.user_id and u.account_id_in_use = ual.account_id and have tried to move this condition to a where clause which still provides an empty result.
'u.account_id_in_use', '=', 'ual.account_id' are both integers however replacing u.account_id_in_use with a hardcoded integer e.g. 2 would return a result. Therefore, Laravel seems to have an issue with this field and replaced the where-> with a whereRaw now returns the desired result.
For anyone having a similar issue, try replacing fields with hardcode values to isolate the issue and look into using raw when possible to overcome the issue.
Hope this helps anyone in need.

Doctrine Left join with limit

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());

Doctrine query only returning one row?

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)

Resources