Convert This Sql to Eloquent - mysql

How can I create this query with Eloquent?
SELECT
*
FROM
`contents`
WHERE
`id` NOT IN (
SELECT
`id`
FROM
`contents` AS `laravel_reserved_0`
WHERE
`laravel_reserved_0`.`parent_id` IN (
SELECT
`id`
FROM
`contents` AS `laravel_reserved_1`
WHERE
`laravel_reserved_1`.`type` IN ( 'pro' )
)
)
AND `is_active` = 1
AND `type` IN ( 'stars', 'video', 'article' )
GROUP BY
`slug`
ORDER BY
`created_at` DESC
LIMIT 10

You can do multiple queries, separate for nested queries.
$typeIDs = Content::whereIn('type', ['pro'])->pluck('id');
$parentIDs = Content::whereIn('parent_id', $typeIDs)->pluck('id');
$contents = Content::whereNotIn('id', $parentIDs)
->where('is_active', 1)
->whereIn('type', ['stars', 'video', 'article'])
->groupBy('slug')
->orderBy('created_at', 'desc')
->limit(10)
->get();
Beside this, if you wish, you can also replace created variables with the actual queries itself.

Related

Get 2 Previous and Next with Current entry from database in laravel

I'm showing the image on a page. I am getting data with this
$designs = Design::take(10)->where('show', '1')->where('id', $id)->orderBy('hit', 'desc')->get();
Now I want 2 previous and 2 next records so users can select and see them.
Something like
Select 5 entry where the middle should be 'id'
The solution I came up with is the following:
You find the middle design.
Using it's id, you can get the previous 2 and make an union with a similar query that gets the next 2 (along with the original).
$design = Design::select('id')
->where('name', 'Sunset')
->firstOrFail();
$designs = Design::query()
->where('id', '<', $design->id)
->orderByDesc('id')
->limit(2)
->union(
Design::query()
->where('id', '>=', $design->id)
->orderBy('id')
->limit(3)
)
->orderBy('id')
->get();
The SQLs generated by this query are the following:
SELECT `id` FROM `designs`
WHERE `name` = "Sunset"
LIMIT 1
(
SELECT * FROM `designs`
WHERE `id` < ?
ORDER BY `id` DESC
LIMIT 2
)
UNION
(
SELECT * FROM `designs`
WHERE `id` >= ?
ORDER BY `id` ASC
LIMIT 3
)
ORDER BY `id` ASC
... Or if you'd rather have the results more separated
$design = Design::where('name', 'Sunset-Image')->firstOrFail();
$previous = Design::where('id', '<', $design->id)->orderByDesc('id')->limit(2)->get();
$next = Design::where('id', '>', $design->id)->orderBy('id')->limit(2)->get();

Order query by subquery. Eloquent vs MySql

I would like to get lists which are followed by a particular user and order lists by created_at(by date when lists were followed). Not sure why it doesn't work (order by) using Eloquent:
$myQuery = PlaceList::query()
->where('private', 0)
->whereHas('followers', function ($query) use ($userID) {
$query->where('created_by_user_id', $userID);
})
->orderByDesc(
Follow::query()->select('created_at')
->where('created_by_user_id', $userID)
->where('followable_id', 'place_lists.id')
)
->get()
This is what I've got when I use dd($myQuery->toSql()):
select
*
from
`place_lists`
where
`private` = ?
and exists (
select
*
from
`follows`
where
`place_lists`.`id` = `follows`.`followable_id`
and `created_by_user_id` = ?
and `follows`.`deleted_at` is null
)
and `place_lists`.`deleted_at` is null
order by (
select
`created_at`
from
`follows`
where
`created_by_user_id` = ?
and `followable_id` = ?
and `follows`.`deleted_at` is null
) desc
But when I populate MySql with data it does work:
select
*
from
`place_lists`
where
`private` = 0
and exists (
select
*
from
`follows`
where
`place_lists`.`id` = `follows`.`followable_id`
and `created_by_user_id` = 13
and `follows`.`deleted_at` is null
)
and `place_lists`.`deleted_at` is null
order by (
select
`created_at`
from
`follows`
where
`created_by_user_id` = 13
and `followable_id` = `place_lists`.`id`
and `follows`.`deleted_at` is null
) desc
I'm well confused, what I'm doing wrong?
This query, you assert that followalbe_id is equal to 'place_lists.id'.
->orderByDesc(
Follow::query()->select('created_at')
->where('created_by_user_id', $userID)
->where('followable_id', 'place_lists.id')
)
To compare two columns use whereColumn() instead.
->orderByDesc(
Follow::query()->select('created_at')
->where('created_by_user_id', $userID)
->whereColumn('followable_id', 'place_lists.id')
)
I'm not sure if I'm on the right track here but in line 9 of your eloquent builder the query generated will use a string to compare followable_id against and therefore look like this:
and `followable_id` = 'place_lists.id'
Using DB::raw() in your where-clause in line 9 should fix that:
$myQuery = PlaceList::query()
->where('private', 0)
->whereHas('followers', function ($query) use ($userID) {
$query->where('created_by_user_id', $userID);
})
->orderByDesc(
Follow::query()->select('created_at')
->where('created_by_user_id', $userID)
->where('followable_id', DB::raw('`place_lists`.`id`')) // here
)
->get()

Mysql not working correctly with and

i have the SQL statement:
SELECT `id`, `un`, `last_active`
FROM `users`
WHERE (`company_id` = :company_id
AND `un` LIKE :un
AND `id` != :id
AND `id` != :id)
ORDER BY id DESC
LIMIT 1
But this doesn't work correctly because i suspect that the repetitive component id is not being tested correctly.
So how can i have a sql statement with id!=1 AND id!=7

select last row only if a where condition is met

I have a column for messages and I am trying to figure out how I should display messages in "sent" folder.
I run the following query:
SELECT
`text`,
`created`
FROM
`messages`
WHERE
`status` = 1
ORDER BY `created` DESC
LIMIT 1
I want to introduce a condition so that result is returned only when the last row with status = 1 also has user_from = $user (If the last row has user_to = $user, then nothing should be returned).
What should my query be?
you can use a subquery
select `text`, `created` from T1
( SELECT
`text`,
`created`
FROM
`messages`
WHERE
`status` = 1
ORDER BY `created` DESC
LIMIT 1) T1
where `user_from` = $user and `user_to` != $user
If I understand your question correctly, do you want to do this:
SELECT
`text`,
`created`
FROM
`messages`
WHERE
`status` = 1
AND `user_from` = $user
AND `user_to` != $user
ORDER BY `created` DESC
LIMIT 1
Of course you need to replace $user with your string, or use a prepared statement to insert the variable into the query.
Select the latest message with status=1 and then use it as a nested query and check your conditions to output this one row result or not:
select `text`, `created`
from
(
SELECT
`text`,
`created`,
user_from,
user_to
FROM
`messages`
WHERE
`status` = 1
ORDER BY `created` DESC
LIMIT 1
) t
where (user_from = $user)
and (not (user_to = $user))

How do I combine these two Select queries with an OR case

I want to select all rows where WHERE (uid = {$uid} OR uid = **HERE** ) where **HERE** is the cids retreived from query 2 below.
Query 1:
SELECT * FROM `t_activities`
WHERE (`uid` = {$uid} OR `uid` = **HERE** )
AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10
And Query 2:
SELECT `cid` FROM `t_con` WHERE `uid` = {$uid} AND `flag` = 1
SELECT * FROM `t_activities`
WHERE (`uid` = {$uid} OR `uid` in (SELECT `cid`
FROM `t_con`
WHERE `uid` = {$uid} AND `flag` = 1))
AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10
You can do this as a join as well:
SELECT *
FROM `t_activities` ta left outer join
(SELECT `cid`
FROM `t_con`
WHERE `uid` = {$uid} AND `flag` = 1)
) tc
on ta = tc.cid
WHERE (`uid` = {$uid} OR tc.`uid` is not null) AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10
By the way, as a SQL statement the "GROUP BY fid" looks very strange. This is allowed in mysql, but I think it is a bad practice. It is much better to be explicit about what you are doing:
SELECT fid, min(<field1>) as Field1, . . .
This helps prevent mistakes when you go back to the query or try to modify it.