I am currently working on a Lumen based application and I am stuck on an Eloquent/Laravel query. What I am currently working on is this:
$min = $filter['min_spending']*100;
$query = User::isCustomer()
->with("interests")
->leftJoin("points_history", "points_history.user_id", "=", "users.id")
->leftJoin("collections", "collections.user_id", "=", "users.id")
->select("users.*",
DB::raw("(SELECT SUM(amount) FROM points_history
WHERE points_history.user_id = users.id
AND points_history.confirmed = true ) as total_points"),
DB::raw("(SELECT SUM(price) FROM collections
WHERE paid_at IS NOT NULL
AND refunded_at IS NULL
AND collections.user_id = users.id) as total_purchase"),
DB::raw("(SELECT SUM(collections.price)) as current_purchase"))
->where("total_purchase", ">=", $min);
// other relevant code here
$query->groupBy('users.id')->orderBy('users.created_at', 'desc');
However, when I try to get the result, I get this error:
{"error":"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'total_purchase >=' in 'where clause' (SQL: select count(*) as aggregate from `users` left join `points_history` on `points_history`.`user_id` = `users`.`id` left join `collections` on `collections`.`user_id` = `users`.`id` where `users`.`deleted_at` is null and `role` = 2 and `total_purchase >=` = 200000 group by `users`.`id`)"}
The subqueries did not seem to register which is causing the problem (?) My desired SQL Statement is this:
SELECT users . *,
(SELECT
SUM(amount)
FROM
points_history
WHERE
points_history.user_id = users.id
AND points_history.confirmed = true) AS total_points, (SELECT
SUM(price)
FROM
collections
WHERE
paid_at IS NOT NULL
AND refunded_at IS NULL
AND collections.user_id = users.id) AS total_purchase, SUM(collections.price) AS current_purchase
from
users
left join
points_history ON points_history.user_id = users.id
left join
collections ON collections.user_id = users.id
where
users.deleted_at is null AND (SELECT
SUM(price)
FROM
collections
WHERE
paid_at IS NOT NULL
AND refunded_at IS NULL
AND collections.user_id = users.id) >= 200000
GROUP BY users.id
where 200000 is $min. Could anyone help me pinpoint what the problem is in my query so I can figure out how to fix it?
You should try this:
$min = $filter['min_spending']*100;
$query = User::isCustomer()
->with("interests")
->leftJoin("points_history", "points_history.user_id", "=", "users.id")
->leftJoin("collections", "collections.user_id", "=", "users.id")
->select("users.*",
DB::raw("(SELECT SUM(amount) FROM points_history
WHERE points_history.user_id = users.id
AND points_history.confirmed = true ) as total_points"),
DB::raw("(SELECT SUM(price) FROM collections
WHERE paid_at IS NOT NULL
AND refunded_at IS NULL
AND collections.user_id = users.id) as total_purchase"),
DB::raw("(SELECT SUM(collections.price)) as current_purchase"))
->where("total_purchase", '>=', $min);
// other relevant code here
$query->groupBy('users.id')->orderBy('users.created_at', 'desc');
->where("total_purchase",">=", $min);
In the quick view, you did not put "," in the last line
FIXED:
Apparently, SELECT does not take multiple args but it accepts an array
->select(["users.*",
DB::raw("(SELECT SUM(amount) FROM points_history
WHERE points_history.user_id = users.id
AND points_history.confirmed = true ) as total_points"),
DB::raw("(SELECT SUM(price) FROM collections
WHERE paid_at IS NOT NULL
AND refunded_at IS NULL
AND collections.user_id = users.id) as total_purchase"),
DB::raw("(SELECT SUM(collections.price)) as current_purchase")]
Also ended up changing the WHERE clause to
$query->whereRaw(DB::raw("(SELECT SUM(amount) FROM points_history
WHERE points_history.user_id = users.id
AND points_history.confirmed = true ) <= " . $max));
with a dot instead of a comma to concatenate to the query
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 have the following SQL
SELECT C.CUOCODE, C.NAME, COUNT(*) TOTAL_PAYMENT, SUM(P.AMOUNT) TOTAL_AMOUNT
FROM TAX_PAYMENT P
INNER JOIN TAX_CHECKPOINT C ON C.CUOCODE = REGEXP_SUBSTR(P.INVOICEID, 'R....')
WHERE DELETED = 0 AND TO_CHAR(TXTIME,'YYYY-MM-DD') = '2018-04-24'
GROUP BY C.CUOCODE, C.NAME
ORDER BY TOTAL_AMOUNT DESC;
How can i convert to laravel eloquent, i have "Payment" model (table TAX_PAYMENT) with "paymentid" as primary key.
DB::table('TAX_PAYMENT as P')
->select([
'C.CUOCODE',
'C.NAME',
DB::raw('COUNT(*) AS TOTAL_PAYMENT'),
DB::raw('SUM(P.AMOUNT) AS TOTAL_AMOUNT'),
])->Join('TAX_CHECKPOINT C', 'C.CUOCODE', '=', DB::raw('REGEXP_SUBSTR(P.INVOICEID,'R....')'))
->where('DELETED', 0)
->where(DB::raw("TO_CHAR(TXTIME,'YYYY-MM-DD')"), '2018-04-24')
->groupBy('C.CUOCODE')
->groupBy('C.NAME')
->orderBy('TOTAL_AMOUNT', 'desc')
->toSql();
output
SELECT
`C`.`CUOCODE`,
`C`.`NAME`,
COUNT(*) AS TOTAL_PAYMENT,
SUM(P.AMOUNT) AS TOTAL_AMOUNT
FROM
`TAX_PAYMENT` AS `P`
INNER JOIN `TAX_CHECKPOINT C` ON `C`.`CUOCODE` = REGEXP_SUBSTR (P.INVOICEID,"R....")
WHERE
`DELETED` = ?
AND TO_CHAR (TXTIME, 'YYYY-MM-DD') = ?
GROUP BY
`C`.`CUOCODE`,
`C`.`NAME`
ORDER BY
`TOTAL_AMOUNT` DESC
A quick and dirty way would be to use Eloquents select raw like:
$result = DB::select( DB::raw("SELECT C.CUOCODE, C.NAME, COUNT(*)
TOTAL_PAYMENT, SUM(P.AMOUNT) TOTAL_AMOUNT FROM TAX_PAYMENT INNER JOIN
TAX_CHECKPOINT C ON C.CUOCODE
= REGEXP_SUBSTR(P.INVOICEID, 'R....') WHERE DELETED = 0 AND
TO_CHAR(TXTIME,'YYYY-MM-DD') = '2018-04-24' GROUP BY C.CUOCODE,
C.NAME ORDER BY TOTAL_AMOUNT DESC"));
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 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
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..