Laravel 5.6 Custom Query Build showing empty result - laravel-5.6

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.

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.

Laravel Query Builder - IN operator

I'm trying to build a query joining multiple tables and I'm having trouble writing a join using an IN operator. Here's an example:
LEFT JOIN sProductDetailWarehouse pdw ON (pdw.ID_sProductDetail = pd.ID AND pdw.ID_sWarehouse IN (52,118))
The two values are set and don't need to be parameters....but this doesn't work since there is no IN operator:
->leftJoin('sProductDetailWarehouse as pdw', function($join)
{
$join->on('pdw.ID_sProductDetail', '=', 'pd.ID');
$join->on('pdw.ID_sWarehouse','IN',DB::raw("(52,118)"));
})
How can I do that join? I'm sure there's a way to do it, I just can't find it...
When you need to join to data you need to use a 'where' method instead of 'on'
e.g.
->leftJoin('sProductDetailWarehouse as pdw', function($join)
{
$join->on('pdw.ID_sProductDetail', '=', 'pd.ID');
$join->whereIn('pdw.ID_sWarehouse',[52,118]);
})

What is wrong with laravel query builder query?

I have written a query to fetch the data from mysql database using laravel query builder. Take a look at query builder code given below:
$products = DB::table("products as p")
->select("p.*")
->join("product_tag as pt", "pt.p_id", "p.id")
->whereIn("pt.tag_name", function($q1) use($request){
$q1->from("user_questionnaire as uc")
->select(DB::raw("distinct(at.prod_tag)"))
->join("questionnaire_answers as qa", function($join){
$join->on("qa.question_id", "=", "uc.question_id")
->where("qa.answer_number", "=", "uc.answer_id");
})
->join("answer_tags as at", "at.answer_id", "qa.id")
->where("uc.user_id", $request->user_id);
})->get();
When i log this query builder, i get below response:
[
{
"query": "select `p`.* from `products` as `p` inner join `product_tag` as `pt` on `pt`.`p_id` = `p`.`id` where `pt`.`tag_name` in (select distinct(at.prod_tag) from `user_questionnaire` as `uc` inner join `questionnaire_answers` as `qa` on `qa`.`question_id` = `uc`.`question_id` and `qa`.`answer_number` = ? inner join `answer_tags` as `at` on `at`.`answer_id` = `qa`.`id` where `uc`.`user_id` = ?)",
"bindings": [
"uc.answer_id",
115
],
"time": 0.43
}
]
Now when i run this query in phpmyadmin, it returns desired results. But when print_r $products variable, it displays empty array([]).
Please suggest what i am doing wrong in query builder.
Your problem is that you're using a ->where() to apply extra criteria to your innermost join:
->where("qa.answer_number", "=", "uc.answer_id");
In this case, the 3rd parameter is being bound into the query as a string so your database will be comparing the qa.answer_number field to the string uc.answer_id which is probably not what you're looking for. When you do a where, the 3rd (or the 2nd if you omit the operator) will always be added to the query bindings which is what results in this behaviour.
To get around this, you should use another ->on(...) to add additional criteria to the join:
$join->on("qa.question_id", "=", "uc.question_id")
->on("qa.answer_number", "=", "uc.answer_id");
That will make sure that the database is comparing columns to columns rather than columns to values.

How to Join same table in laravel

I wan to wirte a join query to connect same table, and without ON, but when i write it in laravel without on it is showing error
$key = DB::table('api_keys as ak')
->join('api_keys as bk','')
->where('ak.api_key', $api_key)->where('ak.user_id',0)
->pluck('api_key');
want to build the below query,
SELECT * FROM `api_keys` as ak
JOIN `api_keys` as bk
WHERE ak.`api_key`=$akey
and ak.`user_id`=$auser
and bk.`user_id`=$bsuer
and bk.`api_key`=$bkey
You must provide an ON clause for the join. More about where ON clauses are required can be found in this answer.
You can view the generated query using toSql() on a QueryBuilder object:
echo $key = DB::table('api_keys as ak')
->join('api_keys as bk','')
->where('ak.api_key', $api_key)->where('ak.user_id',0)
->toSql();
Which in your case returns:
select * from `api_keys` as `ak` inner join `api_keys` as `bk`
on `` `` where `ak`.`api_key` = ? and `ak`.`user_id` = ?
In your case it isn't totally clear what you are trying to achieve, but you might consider joining on api_key or the primary key of the api_keys table, if that is different:
$key = DB::table('api_keys as ak')
->join('api_keys as bk','ak.api_key', '=', bk.api_key)
->where('ak.api_key', $api_key)->where('ak.user_id',0)
->pluck('api_key');
DB::table('registerusers as a')
->join('registerusers as b', 'a.id', 'b.refer_id')
->where('a.username', 'b.username')
->where('b.id', 'a.refer_id')
->value('b.id');
without using on clause in laravel query builder you can use following
$key = DB::table(DB::raw('api_keys as ak, api_keys as bk'))
->where('ak.api_key', '=', $api_key)
->where('ak.user_id','=',0)
->where('ak.PK','=','bk.PK')
->pluck('ak.api_key')
where PK references to your table's primary key.
result will in your case.
select * from api_keys as ak, api_keys as bk where ak.api_key= 'api_key_value' and ak.user_id = 0 and ak.PK = bk.PK
I solved this by creating my own class and starting out with a base query which I modify to apply the join (using Laravel's joinSub function) as follows:
public function __construct()
{
$this->query = DB::table('question_responses as BASE');
}
public function applyFilter($questionId, $questionValue) {
$filterTableStr = 'filter_table_'.$questionId;
$filterIdStr = 'filter_id_'.$questionId;
$filterQuery = DB::table('question_responses AS '.$filterTableStr)
->select('survey_response_id AS '.$filterIdStr)
->where($filterTableStr.'.question_short_name', $questionId)
->where($filterTableStr.'.value', $questionValue);
$resultTableStr = 'result_table_'.$questionId;
$this->query = $this->query
->joinSub($filterQuery, $resultTableStr, function($join) use ($resultTableStr, $filterIdStr) {
$join->on('BASE.survey_response_id', '=', $resultTableStr.'.'.$filterIdStr);
});
}
After applying my required filters I can just call $this->query->get() as normal to obtain the result.
The important part was to make sure that each resulting table and join fields has unique names.
With this method I can apply unlimited filters to my base query.

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