I have the following query and it's doing it's job fine:
SELECT exams.id, exams.date FROM exams
WHERE exams.modul_id = (SELECT questions.modul_id FROM questions where questions.id = 5)
AND NOT EXISTS (
SELECT * FROM exam_question, questions
WHERE questions.id = 5
AND questions.id = exam_question.question_id
AND exam_question.exam_id = exams.id
)
It returns me all exams that belong to the same model as exam but not connteced to exam yet.
I want to use this query in Laravel but I always get an empty result back (it shouldn't be empty)
DB::table('exams')
->select(['id', 'date'])
->whereRaw('modul_id = '.$question->modul_id)
->whereNotExists(function ($query) use ($question) {
$query->select(DB::raw(1))
->from('questions as q')
->join('exam_question as eq', 'q.id', '=', 'eq.question_id')
->join('exams as e', 'eq.exam_id', '=', 'e.id')
->whereRaw('q.id = '.$question->id);
})
->get();
The output of the laravel expression is:
select `id`, `date` from `exams` where modul_id = 1 and not exists (select 1 from `questions` as `q` inner join `exam_question` as `eq` on `q`.`id` = `eq`.`question_id` inner join `exams` as `e` on `eq`.`exam_id` = `e`.`id` where q.id = 5)
I see problem in your sql query dump in section and not exists (... you select starts with select 1 from it will always select number 1 from your table according to selected rows count
select `id`, `date` from `exams`
where modul_id = 1
and not exists (
select 1 from `questions` as `q`
inner join `exam_question` as `eq` on `q`.`id` = `eq`.`question_id`
inner join `exams` as `e` on `eq`.`exam_id` = `e`.`id` where q.id = 5)
You have to use in query builder instead $query->select(DB::raw(1)) ... -> $query->select('*') ...
DB::table('exams')
->select(['id', 'date'])
->whereRaw('modul_id = '.$question->modul_id)
->whereNotExists(function ($query) use ($question) {
$query->select('*')
->from('questions as q')
->join('exam_question as eq', 'q.id', '=', 'eq.question_id')
->join('exams as e', 'eq.exam_id', '=', 'e.id')
->whereRaw('q.id = '.$question->id);
})
->get();
If the rest logic which you used to create your query is correct it will start to work
Related
In Laravel 4.2, I am trying to achieve a query that returns all users, that have all of certain activities. As of now, I have a query that returns all users that have one of many activities:
//$selectedActivities being an array
$userByActivities = User::with('activities')
->whereHas('activities', function($query) use($selectedActivities){
$query->whereIn('id', $selectedActivities);
})->get();
To be more clear: given activities a,b,c. I am looking for all users that have activity a AND b AND c. My query returns all users that have activity a OR b OR c.
Thank you for your help.
EDIT:
The solution offered by lukasgeiter results in following query:
select * from `users` where
(select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '7') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '3') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '1') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '2') >= 1
Whereas the solution offered by Jarek Tkaczyk:
$userByActivities = User::with('activities')
->whereHas('activities', function($query) use($selectedActivities) {
$query->selectRaw('count(distinct id)')->whereIn('id', $selectedActivities);
}, '=', count($selectedActivities))->get();
for a similar request, results in following query:
select * from `users` where (select count(distinct id) from `activities`
inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id`
where `activity_user`.`user_id` = `users`.`id` and `id` in ('7', '3', '1', '2')) = 4
You'll have to add multiple whereHas for that:
$query = User::with('activities');
foreach($selectedActivities as $activityId){
$query->whereHas('activities', function($q) use ($activityId){
$q->where('id', $activityId);
});
}
$userByActivities = $query->get();
If you are getting Cardinality violation: 1241 Operand should contain 2 column(s) the problem is the nested selectCount adds to the normal select count(*) instead of overriding the existing select, so changing to $query->distinct()->whereIn('id', $selectedActivities); did the trick for me, or changing to $query->select(DB::raw(count(distinct id)))
I am new to Laravel and trying to support an existing application that is in Laravel 5. I am trying to convert the following SQL to eloquent structure
SELECT s.id,
CONCAT(u.first_name, ' ', u.last_name) AS user_name,
u.avatar_location AS user_img,
s.employee_photo,
d.name AS department,
seg.name AS segment,
s.survey_title,
s.before_action,
s.before_picture,
s.action,
s.action_date,
s.after_action,
s.after_picture,
s.nominated,
s.awarded,
s.created_at,
s.updated_at,
(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id) AS likes,
(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id AND l.user_id = 5) AS UserLikes,
(SELECT COUNT(1) FROM comments c WHERE c.survey_id = s.id ) AS comments
FROM surveys s
JOIN departments d
ON s.department = d.id
JOIN segments seg
ON s.segment_id = seg.id
JOIN users u
ON s.user_id = u.id
WHERE s.status = 'Approved'
ORDER BY s.action_date DESC
LIMIT 20 OFFSET 20
I know enough Laravel to know that my basic start would probably be
$surveys = DB::table('surveys')
->join('departments', 'surveys.department', '=', 'departments.id')
->join('segments', 'surveys.segment_id', '=', 'segments.id')
->join('users', 'surveys.user_id', '=', 'users.id')
->where('surveys.status', 'Approved')
->orderBy('surveys.action_date')
->skip(20)-take(20)
->select(...)->get();
However, I am not sure how to do the subqueries. Looking for any suggestions.
Thanks!
For select statements, you can use DB::raw().
$surveys = DB::table('surveys')
->join('departments', 'surveys.department', '=', 'departments.id')
->join('segments', 'surveys.segment_id', '=', 'segments.id')
->join('users', 'surveys.user_id', '=', 'users.id')
->where('surveys.status', 'Approved')
->orderBy('surveys.action_date')
->skip(20)-take(20)
->select([DB::raw('(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id) AS likes'),
...
])
->get();
Similarly, select statements would go under the select array. Just so to be clear, the result will be a collection.
I'm having difficulty converting a SQL to the eloquent of laravel, specifically in the part of an inner join, where I make the comparison in a "in" different of the "="
Query:
SELECT
titulo_id as titulo_id,
-- calculate both SUMs, select values for each dependent by what value it matches to
SUM(CASE WHEN ativos_extratos.data_import_id = borders.min_id THEN valor_bruto_atual END) AS valor_min,
SUM(CASE WHEN ativos_extratos.data_import_id = borders.max_id THEN valor_bruto_atual END) AS valor_max,
data_imports.data_import AS created_at,
week(data_imports.data_import) AS weeknumber
FROM
ativos_extratos
INNER JOIN
titulos ON titulo_id = titulos.id
INNER JOIN
representantes ON representante_id = representantes.id
INNER JOIN
data_imports ON data_import_id = data_imports.id
INNER JOIN ( SELECT
MIN(ID) as min_id,
MAX(ID) as max_id
FROM
data_imports
WHERE
data_import BETWEEN '2018-11-01' AND '2018-12-10'
GROUP BY week(data_import)
) borders ON ativos_extratos.data_import_id IN (borders.min_id, borders.max_id)
WHERE
user_id = 1
AND data_imports.data_import BETWEEN '2018-11-01' AND '2018-12-10'
GROUP BY titulos.nome_titulo , weeknumber
Current Eloquent ORM
$rows = AtivosExtrato::select('titulo_id',
DB::raw('SUM(CASE WHEN ativos_extratos.data_import_id = borders.min_id THEN valor_bruto_atual END) AS valor_init'),
DB::raw('SUM(CASE WHEN ativos_extratos.data_import_id = borders.max_id THEN valor_bruto_atual END) AS valor_end'),
'data_imports.data_import AS created_at',
DB::raw('month(data_imports.data_import) AS weeknumber')
)
->join('titulos','titulo_id', '=', 'titulos.id' )
->join('representantes','representante_id', '=', 'representantes.id' )
->join('data_imports','data_import_id', '=', 'data_imports.id' )
->join(DB::raw("
( SELECT
MIN(ID) as min_id,
MAX(ID) as max_id
FROM
data_imports
WHERE
data_import BETWEEN '2018-10-01' AND '2018-12-10'
GROUP BY month(data_import)) borders
"), function ($join){
$join->on('ativos_extratos.data_import_id', 'in', "(borders.min_id, borders.max_id')");
})
->where('user_id', Auth::user()->id)
->whereBetween('data_import', ['2018-01-01', '2018-12-10'])
->groupBy('titulos.nome_titulo')
->groupBy('weeknumber')
->orderBy('data_import')
->orderBy('titulos.nome_titulo')
->get();
The problem is at the time I do the join using the "in", but it does not run as it should, it concatenates "=" and other fields.
You can try to use whereIn,
Here is an example :
$users = DB::table('users')
->whereIn('id', array(1, 2, 3))->get();
Try something like :
$join->whereIn('ativos_extratos.data_import_id', '(borders.min_id, borders.max_id)');
instead of $join->on('ativos_extratos.data_import_id', 'in', "(borders.min_id, borders.max_id')");
More documentation: https://laravel.com/docs/5.0/queries and
https://github.com/illuminate/database/blob/master/Query/Builder.php#L824
I am using following query to retrieve the user feeds but ordering latest update is not working when we applying order created_at time by desc
Here i have given SQL query. Kindly suggest me solution to solve my problem
select `users`.`id` as `uid`, `updates`.`post_id`, `updates`.`id` as `upid`, `friends`.`id` as `fid`, `updates`.`user_id`, `updates`.`privacy`, `updates`.`updated_at`, `updates`.`created_at`, `friends`.`first_user_id`, `friends`.`second_user_id`, `friends`.`friend_status`, `updates`.`update_type` from `updates`
inner join `users` on `updates`.`user_id` = `users`.`id`
inner join `friends` on
CASE
WHEN friends.first_user_id = 1
THEN friends.second_user_id = updates.user_id
WHEN friends.second_user_id= 1
THEN friends.first_user_id = updates.user_id
END
where `friends`.`friend_status` > 0
and `updates`.`privacy` in (1,2)
and `updates`.`user_id` != 1 and
`updates`.`deleted_at` is null
group by `updates`.`post_id`
order by `updates`.`created_at` desc
Laravel Code
Update::select(
'users.id as uid', 'posts.id as pid', 'updates.post_id', 'updates.id as upid',
'friends.id as fid', 'updates.user_id', 'updates.privacy', 'updates.updated_at', 'updates.created_at', 'posts.deleted_at', 'friends.first_user_id',
'friends.second_user_id', 'friends.friend_status', 'updates.update_type', 'posts.wall_user_id'
)->join('users', 'updates.user_id', '=', 'users.id')
->join('posts', 'posts.id', '=', 'updates.post_id')
->join('friends', function($join) use ($userId){
$join->on(DB::raw('CASE
WHEN friends.first_user_id = '.$userId.'
THEN friends.second_user_id = updates.user_id
WHEN friends.second_user_id= '.$userId.'
THEN friends.first_user_id = updates.user_id
END'
), DB::raw(''), DB::raw(''));
})->where('friends.friend_status', '>', 0)
->whereIn('updates.privacy', [1,2])
->where('updates.user_id', '!=', Auth::user()->id)
->groupBy('updates.post_id')
->orderBy('updates.created_at', 'DESC')
->get();
select * from(select `users`.`id` as `uid`, `updates`.`post_id`, `updates`.`id` as `upid`, `friends`.`id` as `fid`, `updates`.`user_id`, `updates`.`privacy`, `updates`.`updated_at`, `updates`.`created_at`, `friends`.`first_user_id`, `friends`.`second_user_id`, `friends`.`friend_status`, `updates`.`update_type` from `updates`
inner join `users` on `updates`.`user_id` = `users`.`id`
inner join `friends` on
CASE
WHEN friends.first_user_id = 1
THEN friends.second_user_id = updates.user_id
WHEN friends.second_user_id= 1
THEN friends.first_user_id = updates.user_id
END
where `friends`.`friend_status` > 0
and `updates`.`privacy` in (1,2)
and `updates`.`user_id` != 1 and
`updates`.`deleted_at` is null order by `updates`.`created_at` desc) as tmp_table
group by `updates`.`post_id`
I would know how to perform an 'Advanced Where'.
I didn't find anything in the documentation that explain what I want.. even there.
(cf: http://laravel.com/docs/4.2/queries#advanced-wheres).
Post::whereHas('international_post_en', function($q) {
$q->where('is_published', 1);
})->whereHas('categories', function($q) {
$q->where('name', 'test-one');
})->orWhereHas('subcategories', function($q) {
$q->where('name', 'test-two');
})->with('categories', 'subtags')
->get();
My query look like this:
select * from `posts` where `posts`.`deleted_at` is null and (select count(*) from `international_posts_en` where `international_posts_en`.`posts_id` = `posts`.`id` and `is_published` = ?) >= 1 and (select count(*) from `categories` inner join `posts_has_categories` on `categories`.`id` = `posts_has_categories`.`categories_id` where `posts_has_categories`.`posts_id` = `posts`.`id` and `name` = ?) >= 1 or (select count(*) from `subcategories` inner join `posts_has_subcategories` on `subcategories`.`id` = `posts_has_subcategories`.`subcategories_id` where `posts_has_subcategories`.`posts_id` = `posts`.`id` and `name_en` = ?) >= 1
But I want my query to look like this:
select * from `posts` where `posts`.`deleted_at` is null and (select count(*) from `international_posts_en` where `international_posts_en`.`posts_id` = `posts`.`id` and `is_published` = ?) >= 1 and [(](select count(*) from `categories` inner join `posts_has_categories` on `categories`.`id` = `posts_has_categories`.`categories_id` where `posts_has_categories`.`posts_id` = `posts`.`id` and `name` = ?) >= 1 or (select count(*) from `subcategories` inner join `posts_has_subcategories` on `subcategories`.`id` = `posts_has_subcategories`.`subcategories_id` where `posts_has_subcategories`.`posts_id` = `posts`.`id` and `name_en` = ?) >= 1[)]
(Sorry It is not very readable)
You can see the changes within the brackets.
So, I want the whereHas and the orWhereHas clause to be grouped within parenthesis.
Is it possible with the Laravel Query Builder or should I make a handmade query?
Thank you in advance.
Post::whereHas('international_post_en', function($q) {
$q->where('is_published', 1);
})->where(function ($q) {
$q->whereHas('categories', function($q) {
$q->where('name', 'test-one');
})->orWhereHas('subcategories', function($q) {
$q->where('name', 'test-two');
});
})->with('categories', 'subtags')->get();
In fact this is the very first example on the page you linked. However that example is pretty inaccurate, since you wouldn't group and wheres against or where, but the other way around..