Doctrine Query on Many to One relationship - mysql

In my Padel project on Symfony2 I have a Competition - Registration relationship
On the "Competition" entity:
/**
* #ORM\OneToMany(targetEntity="Registration", mappedBy="competition")
*/
protected $registrations;
On the "Registration" entity:
/**
* #ORM\ManyToOne(targetEntity="PadelSchedule\UserBundle\Entity\User", inversedBy="registrations")
* #ORM\JoinColumn(name="idPlayer", referencedColumnName="id")
*/
private $player;
/**
* #ORM\ManyToOne(targetEntity="Competition", inversedBy="registrations")
* #ORM\JoinColumn(name="idCompetition", referencedColumnName="id")
*/
private $competition;
Something like this. What I need to do is, having the id of the player, get a list of the competitions on which this player is registered.
The close thing that I have get is using a join with this query:
$qb = $em->createQueryBuilder()
->select('r, c')
->from('PadelScheduleMainBundle:Registration', 'r')
->leftJoin('r.competition', 'c')
->where('r.player = :idPlayer')
->setParameter('idPlayer', $idPlayer);
But as it seems by the error I get, what I think I get through this is a list of Registrations with the competition joined, but I need for my view is a list of "Competition" objects.
Any help? Thanks!

Since you select from your Registration entity you get a result of Registrations. Maybe you have better luck using a query like this:
$em->createQueryBuilder()
->select('c')
->from('PadelScheduleMainBundle:Competition', 'c')
->innerJoin('c.registrations', 'r')
->where('r.player = :player')
->setParameter('player', $playerId)

According to your query question.. I have write this query ..Please Try with this query:
$query = $em->createQuery(
'SELECT c
FROM PadelScheduleMainBundle:Competition c
INNER JOIN c.registrations r
WHERE r.player = :idPlayer')
->setParameter('idPlayer', $idPlayer);

Related

Laravel Query builder - select top 1 row from another table

I have this SQL query for MySQL which works fine. But I need to rewrite it using query builder and need to avoid DB::raw() completely because development database is different from production. I know far from ideal, but unfortunately it is what it is.
SELECT athletes.*,
(
SELECT performance
FROM performances
WHERE athletes.id = performances.athlete_id AND performances.event_id = 1
ORDER BY performance DESC
LIMIT 0,1
) AS personal_best
FROM athletes
ORDER BY personal_best DESC
Limit 0, 100
And I'm struggling how to rewrite the personal_best part. I have table of performances for athletes and I need to select only the best performance for each athletes as his personal best.
I was trying to search for answer but all of the answers I found included raw adding raw SQL.
Any ideas or hint would be much appreciated.
Thank you in advance!
So I accepted I might have to use Eloquent for this, but still having trouble to progress. Heres my code:
class Athlete extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'athletes';
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* #var bool
*/
public $timestamps = false;
/**
* Get the performances for the Athelete post.
*
* #return HasMany
*/
public function performances()
{
return $this->hasMany('App\EloquentModels\Performance', 'athlete_id');
}
}
class Performance extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'performances';
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* #var bool
*/
public $timestamps = false;
}
Create a new connection at database.php like mysql_dev for development parameters.
DB::connection('mysql_dev')->table('athletes')
->leftJoin('performances','athletes.id','performances.athlete_id')
->where('performances.event_id',1)
->groupBy('athletes.id')
->orderByDesc('personal_best')
->select('athletes.*',DB::raw('MAX(performances.performance) AS personal_best')
->paginate(100);
try like this without raw,
DB::connection('mysql_dev')->table('athletes')
->leftJoin('performances','athletes.id','performances.athlete_id')
->where('performances.event_id',1)
->groupBy('athletes.id')
->orderByDesc('performances.performance')
->select('athletes.*','performances.performance'
->paginate(100);
If you are using raw SQL just do MAX for performance for each athlete using GROUP BY.
SELECT athletes.*, MAX(performance) AS personal_best
FROM athletes
INNER JOIN performances ON athletes.id = performances.athlete_id AND performances.event_id = 1
GROUP BY athletes.id
ORDER BY personal_best DESC
LIMIT 0, 100
Laravel Query Builder:
DB::table('athletes')
->join('performances', 'athletes.id', '=', 'performances.athlete_id')
->where('performances.event_id', '=', 1)
->groupBy('athletes.id')
->orderBy('personal_best', 'desc')
->select('athletes.*',DB::raw('MAX(performance) AS personal_best')
->limit(100);
Doc says that we can do max(personal_best) but not sure how to use it with group by.
I'm afraid you can't avoid DB::raw in Query Builder but you can use eloquent model for the same, as answered by Shaielndra Gupta.
For that you can create model and relationship.
1. Create Model:
php artisan make:model Athelete
php artisan make:model Performance
2. Create relationship between Athelete and Perforamnce.
Update Athelete.php
/**
* Get the performances for the Athelete post.
*/
public function performances()
{
return $this->hasMany('App\Performance');
}
3. Get data(didn't verify by myself)
$data = Athelete::with('performances',function ($query) use ($eventId){
$query->max('performance')
$query->where('event_id',$eventId)
$query->orderBy('performance');
})->get();
Reference:
Laravel Model
Laravel Relationship
You can use like below.
$sql1 = "(
SELECT performance
FROM performances
WHERE athletes.id = performances.athlete_id AND performances.event_id = 1
ORDER BY performance DESC
LIMIT 0,1
) AS personal_best";
$sql2 = "SELECT athletes.*,$sql1
FROM athletes
ORDER BY personal_best DESC
Limit 0, 100";
$result = DB::select($sql2);
you can user Eloquent ORM like this
$data = Athelete::with('performances',function ($query) use ($eventId){
$query->max('performance')
$query->where('event_id',$eventId)
$query->orderBy('performance');
})->get()

Implementing a join in doctrine query builder not working correctly

I am trying to get information from one table based on information in another table, which is linked by an ID.
The two tables are: property and unit.
I need to gather all the units within a property but ONLY if the property has a status of '1' and a hidden flag of '0'. In normal mySQL, I wrote:
SELECT u.* FROM unit u INNER JOIN property p ON p.id = u.property WHERE p.status = 1 AND p.hidden = 0
which produces the correct results, although when I try the same using querybuilder:
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('u')
->from('AppBundle:Unit', 'u')
->join('u', 'AppBundle:Property', 'p', 'u.property = p.id')
->where('p.status = :status')
->andWhere('p.hidden = :hidden')
->setParameter('status', 1)
->setParameter('hidden', 0);
return $qb->getQuery()->getResult();
Using information I gleaned from the Doctrine Query Builder documentation. However, when I load the page I get the following error:
[Semantical Error] line 0, col 42 near 'u AppBundle:Property': Error:
Class 'u' is not defined.
The query being executed:
SELECT u FROM AppBundle:Unit u INNER JOIN u AppBundle:Property P u.property = p.id WHERE p.status = :status AND p.hidden = :hidden
Can anyone help figure out what I'm doing wrong in my query?
try to change this:
->join('u', 'AppBundle:Property', 'p', 'u.property = p.id')
to this:
->join('AppBundle:Property', 'p', 'WITH', 'u.property = p.id')
You should exchange your first and second arguments places, because join() method is:
/**
* Creates and adds a join over an entity association to the query.
*
* The entities in the joined association will be fetched as part of the query
* result if the alias used for the joined association is placed in the select
* expressions.
*
* <code>
* $qb = $em->createQueryBuilder()
* ->select('u')
* ->from('User', 'u')
* ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
* </code>
*
* #param string $join The relationship to join.
* #param string $alias The alias of the join.
* #param string|null $conditionType The condition type constant. Either ON or WITH.
* #param string|null $condition The condition for the join.
* #param string|null $indexBy The index for the join.
*
* #return QueryBuilder This QueryBuilder instance.
*/
public function join($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
This is a doc from doctrine QueryBuilder class.

Counting rows for the column in mysql

My problem is simple. I have two tables
transaction_bodies
------------------
body_id
full_name
and the other one is
transaction_accounts
--------------------
account_id
body_id
account_name
Relation is one to many. One body can have multiple accounts. I am trying to create a query that counts the accounts that bodies have.
I tried this
SELECT *
FROM
(
SELECT count(*) as trans, tb.full_name
FROM transaction_accounts ta
LEFT JOIN transaction_bodies tb
ON tb.body_id = ta.body_id
) as row;
But this doesn't give the right result. Can anyone help me out with this?
And if can provide how to write sub-queries in Laravel that would be a appreciated much.
Try this :
$result = DB::table('transaction_bodies')
->leftJoin('transaction_accounts as
ta','transaction_bodies.body_id','ta.body_id')
->select(DB::raw('count(ta.account_id) AS trans'),'transaction_bodies.full_name')
->groupBy('transaction_bodies.body_id')
->get();
You can do it with LEFT JOIN, e.g.:
SELECT tb.body_id, COUNT(ta.*)
FROM transaction_bodies LEFT JOIN transaction_accounts ta
ON tb.body_id = ta.body_id
GROUP BY tb.body_id;
With a simple LEFT JOIN you can achieve it like
SELECT tb.full_name, COUNT(account_id) as accounts
FROM transaction_bodies tb LEFT JOIN transaction_accounts ta
ON tb.body_id = ta.body_id
GROUP BY tb.body_id;
In Laravel you can do it like with model
$accounts = Transaction_body::leftJoin('transaction_accounts as ta','transaction_bodies.body_id','ta.body_id')->groupBy('transaction_bodies.body_id')->get();
without model
$accounts = DB::table('transaction_bodies')->leftJoin('transaction_accounts as ta','transaction_bodies.body_id','ta.body_id')->groupBy('transaction_bodies.body_id')->get();
/**
* Class Body
*/
class Body extends Model
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'transaction_bodies';
/**
* Get the accounts for the Transaction Body.
*/
public function accounts()
{
return $this->hasMany(Account::class);
}
}
/**
* Class Account
*/
class Account extends Model
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'transaction_accounts';
/**
* Get the body that owns the account.
*/
public function body()
{
return $this->belongsTo(Body::class);
}
}
//usage
$accounts = Body::find(1)->accounts;
https://laravel.com/docs/5.4/eloquent-relationships#one-to-many

left join with the first entry that is most recently created

I have a fairly complex query as follows:
return $this->createQueryBuilder('s')
->select('s')
->addSelect('COUNT(p.id) as HIDDEN c_id')
->leftJoin('s.owner', 'o')
->leftJoin('s.userPictures', 'p')
->leftJoin('o.transactions', 't')
->leftJoin('t.packType', 'pt')
->where('pt.id =:packId')
->setParameter('packId', $packId)
->andWhere('s.expirydate >=:expiryDate')
->setParameter('expiryDate', new \DateTime('now'))
->andWhere('c_id <:numberOfPictures')
->setParameter('numberOfPictures', $numberOfPictures)
->orderBy("c_id", 'DESC')
->groupBy('p.id')
->getQuery()
;
the problem is that the query is leftJoined with all of it's transactions. I wanted such that it is left joined with the most recent transaction only. How can I do this? Is there an alternative way other than having to find the transaction id of the most recent transaction and put it into the where clause?
The Transaction entity has a created column and the entity looks like this:
class Transaction
{
/**
* #var datetime $created
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
protected $created;
}

Doctrine - Empty leftJoin SQL

I built the following Parts of my Entities :
/**
* #var Application_Model_Ticket
*
* #OneToMany(targetEntity="Application_Model_Ticket",mappedBy="contacts_id")
* #JoinColumn(name="id", referencedColumnName="contacts_id")
*/
private $tickets;
public function getTickets() {
return $this->tickets;
}
/**
* #var Application_Model_Contact
*
* #ManyToOne(targetEntity="Application_Model_Contact",cascade={"persist"})
* #JoinColumn(name="contacts_id", referencedColumnName="id")
*/
private $contact;
public function getContact() {
return $this->contact;
}
When I now try the following Doctrine Code :
$this->oQueryBuilder->select('contact','ticket')
->from('Application_Model_Contact', 'contact')
->leftJoin('contact.tickets', 'ticket')
->orderBy('contact.id', 'DESC');
I get a MYSQL-Error.
The following happens :
FROM contact c0_ LEFT JOIN ORDER BY c0_.id DESC
It seems that Doctrine doesn't fill in the LEFT JOIN properly.
Does anybody have an idea, why this happens ?
UPDATE:
->leftJoin('contact.tickets', 'ticket', 'WITH','contact.id = ticket.contactsId')
Gives me
LEFT JOIN AND (c0_.id = t1_.contacts_id)
you miss the ON in your query
$this->oQueryBuilder
->select('contact','ticket')
->from('Application_Model_Contact', 'contact')
->leftJoin('contact', 'on contact.ticket=Application_Model_Contact.field')
->orderBy('contact.id', 'DESC');
where Application_Model_Contact.field replace it for the match field to apply the JOIN
so your query should be like:
....FROM contact c0_ LEFT JOIN ON table1.field=table2.field ORDER BY c0_.id DESC
Source: http://oldforum.symfony-project.org/index.php/m/69061/
Mysql Join: http://dev.mysql.com/doc/refman/5.0/en/join.html
Try this:
$this->oQueryBuilder->select('contact','ticket')
->from('Application_Model_Contact', 'contact')
->leftJoin('contact.tickets', 'ticket', 'WITH', 'contact.id = ticket.contacts_id')
->orderBy('contact.id', 'DESC');