Issue in Laravel 5.1 Inner Join Query - php

Below is my Query in Laravel 5.1
\App\Models\Project\Bids\ProjectBid_Model
::selectRaw('B.*')
->join('tblproject P','B.projectid','=','P.projectid')
->where('P.WhoCreatedTheProject',14)
->first()
and below is the equivalant query
select B.* from `tblprojectbid`
inner join `tblproject P` on `B`.`projectid` = `P`.`projectid`
where `P`.`WhoCreatedTheProject` = 14 limit 1
What's the problem ?
Please check the line 1 in Query: select B.* from tblprojectbid.
What's the question ?
How can I change
select B.* from tblprojectbid
to
select B.* from tblprojectbid B

If you want to use Eloquent I'm afraid there is no easy way to do it.
I use in this case full table name for model for instance
\App\Models\Project\Bids\ProjectBid_Model
::selectRaw('bid_table.*')
->join('tblproject AS P','bid_table.projectid','=','P.projectid')
->where('P.WhoCreatedTheProject',14)
->first()
However it's also possible that you set alias in ProjectBid_Model:
protected $table = 'bid_table AS B';
The con is you will have this table always aliased with B, so in case you have 2 models with same alias (in this case B), you won't be able to change it later just for one table, so I think the better is 1st approach (without using alias)

Here is the final solution.
\App\Models\Project\Bids\ProjectBid_Model
::selectRaw('B.*')
->from('tblprojectbid as B')
->join('tblproject as P','B.projectid','=','P.projectid')
->where('P.WhoCreatedTheProject',14)
->first()

try this.
\DB::table('tblprojectbid as B')
->select()
->join('tblproject as P','B.projectid','=','P.projectid')
->where('P.WhoCreatedTheProject',14)
->first()

Related

How to do a full join in Laravel Eloquent?

How do I perform a full join given two tables t1 and t2 in laravel eloquent?
If you were using MySQL.
MySQL has no inbuilt support for full outer join.
But you can use the code like this below to achieve that.
$table2 = DB::table('t2')
->rightJoin('t1', 't1.id', '=', 't2.t1_id')
$table1 = DB::table('t1')
->leftJoin('t2', 't1.id', '=', 't2.t1_id')
->unionAll($table1)
->get();
Most of query builder join functions have an optional argument called $type ='inner'
so if you database supports full join (e.g: postgres) just pass "full" as the $type parameter

Laravel 5. Using the USING operator

I tried to find it for a long time, and I can't believe that Laravel doesn't have this functionality.
So, I can write:
select * from a join b where a.id = b.id
or more beautiful:
select * from a join b using(id)
First case is simple for Laravel:
$query->leftJoin('b', 'a.id', '=', 'b.id')
But how to write second case? I expect that it should be simple and short, like:
$query->joinUsing('b', 'id')
But thereis no such method and I can't find it.
PS: it's possible that the answer is very simple, it's just hard to find by word "using", because it's everywhere.
UPDATE
I'm going deeper to source, trying to make scope or pass a function to join, but even inside of this function I can't to anything with this $query. Example:
public function scopeJoinUsing($query, $table, $field) {
sql($query->join(\DB::raw("USING(`{$field}`)")));
// return
// inner join `b` on USING(`id`) ``
// yes, with "on" and with empty quotes
sql($query->addSelect(\DB::raw("USING(`{$field}`)")));
// return
// inner join `b` USING(`id`)
// but in fields place, before "FROM", which is very logic :)
}
So even if forget about scope , I can't do this in DB::raw() , so it's impossible... First time I see that something impossible in Laravel.
So, the answer is - it's impossible.
Laravel doesn't support this functionality, which is really sad.
I fix it in Laravel source code, my PULL REQUEST here - https://github.com/laravel/framework/pull/12773
Nothing is impossible in Laravel.
Until support for join using is added to Laravel core, you can add support for it by installing this Laravel package: https://github.com/nihilsen/laravel-join-using.
It works like this:
use Illuminate\Support\Facades\DB;
use Nihilsen\LaravelJoinUsing\JoinUsingClause;
DB::table('users')->leftJoin(
'clients',
fn (JoinUsingClause $join) => $join->using('email', 'name')
);
// select * from `users` left join `clients` using (`email`, `name`)

Yii2 - left join on multiple condition

I have three tables with the following relations,
------- 1 0..* ------------
|Product|-------------|Availability|
------- ------------
1 |
|
1 |
--------
|MetaData|
--------
my raw sql looks like this
SELECT p.ID FROM product p
LEFT JOIN availability a ON a.productID=p.ID
AND a.start>=DATE_ADD(DATE(now()), INTERVAL 7 DAY)
LEFT JOIN meta_data m ON m.ID=p.meta_dataID
WHERE a.ID IS NULL
AND m.published_state=1;
That is, find each Product with a MetaData.published_state equal to 1 and with no Availability such that Availability.start more than 7 days from now().
I'm trying to accomplish the same using ActiveRecord methods, using something like the following,
$products = Product::find()
->joinWith('metaData')
->joinWith('availability')
->onCondition(['>=', 'availability.start', strtotime('+7 days')])
->where(['is', 'availability.ID', NULL])
->andWhere(['=', 'meta_data.published_state', 1])
->all();
however, this is returning no results. Using Connection::createCommand() to run the raw sql returns the rows I'd expect so there is no issue with the data.
I suspect the issue is being caused by the join conditions and the where conditions 'bleeding' into each other; both join and where being applied to either the joining or the where rather than separately.
How can I output the actual sql query being run? this is in an action being called from a console controller.
How can I alter my code to return the desired Products?
I believe this one is better solution. Instead of using Raw queries like leftJoin you should complement your joinWith relations with andOnCondition (which adds needed where conditions into your join statement).
$products = Product::find()
->joinWith(['metaData' => function (ActiveQuery $query) {
return $query
->andWhere(['=', 'meta_data.published_state', 1]);
}])
->joinWith(['availability' => function (ActiveQuery $query) {
return $query
->andOnCondition(['>=', 'availability.start', strtotime('+7 days')])
->andWhere(['IS', 'availability.ID', NULL]);
}])
->all();
In addition it looks cleaner when you write where clauses inside relations. It works the same as writing it outside (if I'm not wrong), but when refactoring your query, you can easily delete the whole relation without forgetting relation conditions outside.
Just use like below condition.
$query = Product::find()
-> leftJoin('availability', 'availability.productID=product.ID AND a.start>=DATE_ADD(DATE(now()), INTERVAL 7 DAY)')
->leftJoin('meta_data', 'meta_data.ID=product.meta_dataID')
->where(['is', 'availability.ID', NULL])
->andWhere(['=', 'meta_data.published_state', 1])
->all();
Use this:
$sql = 'SELECT p.ID FROM product p
LEFT JOIN availability a ON a.productID=p.ID
AND a.start>=DATE_ADD(DATE(now()), INTERVAL 7 DAY)
LEFT JOIN meta_data m ON m.ID=p.meta_dataID
WHERE a.ID IS NULL
AND m.published_state=1';
$products = Product::findBySql($sql);
Yii Active Record has a findBySql($sql) method that allows you to run and get the data from database using a raw SQL query. It helps a lot when you got confused with Yii's query method or when your query get more complicated to be ran with Yii as in your case I suppose.
So basically, in above block of codes, you just put your raw SQL query to a variable called $sql, and use it as the parameter value of findBySql() method.

Symfony Doctrine, select from subquery with join

Haven't been able to find a solid solution for this, but I have a mySQL query that I want to translate to Doctrine. It is a select from a subquery with joins and I might have read somewhere that joins are not allowed in subqueries in Doctrine.
Here is the SQL:
SELECT part, SUM(qty) as qty FROM (SELECT part, SUM(qty) as qty FROM sub LEFT JOIN main ON main.id = main_id WHERE hold != 1 GROUP BY name, part) AS tbl GROUP BY part
This is what I tried and it is all wrong.
$em = $this->getDoctrine()->getManager();
$q = $em->createQuery('v');
$q2 = $em->createSubQuery()
->select('m.part, sum(s.qty) qty')
->from('Sub s')
->leftJoin('s.main m')
->where('s.hold != 1')
->groupBy('m.part');
$q->select('m.part, sum(qty)', $q2->getDQL());
One of the first error I got was:
FatalErrorException: Error: Call to undefined method Doctrine\ORM\EntityManager::createSubQuery() in ....Controller.php line 238
I am pretty sure it isn't just this that I'm doing wrong but it is the first thing that's coming up. So getManager() apparently doesn't have a createSubQuery() function? What is the right way to do this?
There's no method like createSubQuery(). Take a look at that answer: https://stackoverflow.com/a/10763358

Symfony 2: INNER JOIN on non related table with doctrine query builder

I'm trying to build a query with the doctrine query builder which joins a non related table like this:
$query = $this->createQueryBuilder('gpr')
->select('gpr, p')
->innerJoin('TPost', 'p')
->where('gpr.contentId = p.contentId')
But this doesn't work. I still get an error:
Error: Identification Variable TPost used in join path expression but was not defined before.
I searched for this error message and everybody answered to use the table alias + attribute like p.someAttribute. But the table I want to join isn't related in the table I start my select from.
As a normal mysql query i would write it like this:
SELECT * FROM t_group_publication_rel gpr
INNER JOIN t_post p
WHERE gpr.content_id = p.content_id
Any ideas what i'm doing wrong?
Today I was working on similar task and remembered that I opened this issue. I don't know since which doctrine version it's working but right now you can easily join the child classes in inheritance mapping. So a query like this is working without any problem:
$query = $this->createQueryBuilder('c')
->select('c')
->leftJoin('MyBundleName:ChildOne', 'co', 'WITH', 'co.id = c.id')
->leftJoin('MyBundleName:ChildTwo', 'ct', 'WITH', 'ct.id = c.id')
->orderBy('c.createdAt', 'DESC')
->where('co.group = :group OR ct.group = :group')
->setParameter('group', $group)
->setMaxResults(20);
I start the query in my parent class which is using inheritance mapping. In my previous post it was a different starting point but the same issue if I remember right.
Because it was a big problem when I started this issue I think it could be also interesting for other people which don't know about it.
Joins between entities without associations were not possible until version 2.4, where you can generate an arbitrary join with the following syntax:
$query = $em->createQuery('SELECT u FROM User u JOIN Blacklist b WITH u.email = b.email');
Reference: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html
Want to improve this post? Add citations from reputable sources by editing the post. Posts with unsourced content may be edited or deleted.
$dql = "SELECT
a, md.fisrtName , md.LastName, mj
FROM MembersBundle:Memberdata md
INNER JOIN MembersBundle:Address a WITH md = a.empID
INNER JOIN MembersBundle:Memberjob mj WITH md = mj.memberData
...
WHERE
a.dateOfChange IS NULL
AND WHERE
md.someField = 'SomeValue'";
return $em->createQuery( $dql )->getResult();
A DQL join only works if an association is defined in your mapping. In your case, I'd say it's much easier to do a native query and use ResultSetMapping to populate your objects.

Categories