How to write this (left join, subquery ) in Laravel 5.1? - mysql

How to write this query in Laravel 5.1:
SELECT p.id, p.title, p.created_at, p.updated_at, u.name, COALESCE(c.comments_count, 0) AS comments_count, COALESCE(pl.status_sum, 0) AS status_sum
FROM posts p
LEFT OUTER JOIN users u ON u.id = p.user_id
LEFT OUTER JOIN (
SELECT pl.post_id, SUM(pl.status) AS status_sum
FROM postslikes pl
GROUP BY pl.post_id
) pl ON pl.post_id = p.id
LEFT OUTER JOIN (
SELECT c.post_id, COUNT(*) as comments_count
FROM comments c
GROUP BY c.post_id
) c ON c.post_id = p.id ORDER BY comments_count DESC
I need it for Pagination. I can perform this query raw without any problems but the manually paginator gives always the same results:
http://laravel.com/docs/5.1/pagination#manually-creating-a-paginator
The same problem as here: http://laravel.io/forum/07-22-2015-laravel-51-manual-pagination-not-working-as-expected
My attempt without success:
DB::table( 'posts' )
->select( 'posts.id', 'posts.title', 'posts.created_at', 'posts.updated_at', 'users.name', DB::raw( 'COALESCE( comments.body, 0 ), COALESCE( postslikes.status, 0 )' ) )
->leftJoin( 'users', 'users.id', '=', 'posts.user_id' )
->leftJoin( DB::raw( 'SELECT postslikes.post_id, SUM( postslikes.status ) FROM postslikes GROUP BY postslikes.post_id' ), function( $join )
{
$join->on( 'postslikes.post_id', '=', 'post.id' );
})
->leftJoin( DB::raw( 'SELECT comments.post_id, COUNT(*) FROM comments GROUP BY comments.post_id' ), function( $join )
{
$join->on( 'comments.post_id', '=', 'post.id' );
})
->get();
I think the problem is comments_count and status_sum?
Thanks!

To use subqueries with Laravel's query builder, you should add it to the join as follows:
->leftJoin(DB::raw("(SELECT [...]) AS p"), 'p.post_id', '=', 'posts.id')
It's also better to create an alias for calculated fields, as you did in your raw query:
COUNT(*) AS count
Despite this changes, unless I'm wrong, you can start by making your query simpler. Drop the subqueries, this way:
SELECT
p.id,
p.title,
p.created_at,
p.updated_at,
u.name,
COUNT(c.id) AS comments_count,
COALESCE(SUM(pl.status), 0) AS status_sum
FROM
posts p
LEFT OUTER JOIN
users u
ON
u.id = p.user_id
LEFT OUTER JOIN
postslikes pl
ON
pl.post_id = p.id
LEFT OUTER JOIN
comments c
ON
c.post_id = p.id
ORDER BY
comments_count DESC
GROUP BY
p.id
Then, with this new query, you can use Laravel to build it:
DB::table('posts')
->select([
'posts.id',
'posts.title',
'posts.created_at',
'posts.updated_at',
'users.name',
DB::raw('COUNT(comments.id) AS comments_count'),
DB::raw('COALESCE(SUM(postslikes.status), 0) AS status_sum'),
])
->leftJoin('users', 'users.id', '=', 'posts.user_id')
->leftJoin('comments', 'comments.post_id', '=', 'posts.id')
->leftJoin('postslikes', 'postslikes.post_id', '=', 'posts.id')
->orderBy('comments_count', 'DESC')
->groupBy('posts.id')
->get();
Note that I'm assuming you have a column named id in your comments table that is the primary key.

Related

How to join sub-query in laravel elequent

How do this query in laravel query builder ?
select * from products p join
(
select product_id,sum(qty) total_sales
from orders where qty !=0 group by product_id
)
s on p.id = s.product_id
order by s.total_sales desc
There are different ways are there to do the same thing. But you can do with Raw Expressions is very similar to your above code.
if you want to use Eloquent, Do this provided the orders table has product_id that is a foreign key from products
DB::table('products')->join('orders','products.id','orders.product_id')->where('orders.qty','!=',0)->get()
The first part for sub-query for joined part. It is joined with toSql() method inside the raw statement.
$subQuery = DB::table('orders')
->where('qty', '!=', DB::raw(0))
->groupBy('product_id')
->select('product_id', DB::raw('sum(qty) as total_sales'));
return DB::table('products as p')
->join(DB::raw('(' . $subQuery->toSql() . ') s'), 'p.id', '=', 's.product_id')
->orderByDesc('s.total_sales')
->get();
It prints the following sql;
SELECT *
FROM `products` AS `p`
INNER JOIN (
SELECT `product_id`, SUM(qty) AS total_sales
FROM `orders`
WHERE `qty` != 0
GROUP BY `product_id`
) s ON `p`.`id` = `s`.`product_id`
ORDER BY `s`.`total_sales` DESC

Converting MySQL query to Laravel

How I can convert this MySQL query to a Laravel query?
select *
from marques
where id in (select marque_id from products
where category_id = 'valeur1' or category_id in (select id from categories
where parent_id = 'Valeur1'))
I think your current query is equivalent to the following:
SELECT *
FROM marques m
LEFT JOIN products p
ON m.id = p.marque_id
LEFT JOIN categories c
ON p.category_id = c.id AND c.parent_id = 'Valeur1'
WHERE
p.category_id = 'valeur1' OR
c.id IS NOT NULL
Here is a rough guess at what your Laravel code might look like:
$res = DB::table('marques')
->join('products', 'marques.id', '=', 'products.marque_id')
->join("categories", function($join) {
$join->on('products.category_id', '=', 'categories.id')
->on('categories.parent_id', '=', 'Valeur1')
})
->whereNotNull('categories.id')
->orWhere('products.category_id', '=', 'valeur1')
->select('*')
->get();

How do I select columns from results of union of tables using laravel query builder?

I am trying to convert my mysql statement into laravel query builder. In the following query I am trying to do GROUP BY and ORDER BY on the columns which are fetched from the result of UNION-ing three tables
staff_task_history_calibrate
staff_task_history_samples
staff_task_history_measures
Have you guys come across anything similar to it? If yes, could you please shed some light on my issue?
SELECT staff_name, task_id, task_type, task_desc, SUM(task_multiplier)
FROM
(
(
select CONCAT(S.first_name," ",S.last_name) as staff_name,
`STHC`.`task_id`, IFNULL(T.type, "-") as task_type,
`T`.`description` as `task_desc`,
STHC.task_multiplier
from `staff_task_history_calibrate` as `STHC`
inner join `staffs` as `S` on `STHC`.`staff_id` = `S`.`staff_id` inner join `tasks` as `T` on `STHC`.`task_id` = `T`.`id`
)
union
(
select CONCAT(S.first_name," ",S.last_name) as staff_name,
`STHS`.`task_id`, IFNULL(T.type, "-") as task_type,
`T`.`description` as `task_desc`,
STHS.task_multiplier
from `staff_task_history_samples` as `STHS`
inner join `staffs` as `S` on `STHS`.`staff_id` = `S`.`staff_id` inner join `tasks` as `T` on `STHS`.`task_id` = `T`.`id`
)
union
(
select CONCAT(S.first_name," ",S.last_name) as staff_name,
`STHM`.`task_id`, IFNULL(T.type, "-") as task_type,
`T`.`description` as `task_desc`,
STHM.task_multiplier
from `staff_task_history_measures` as `STHM`
inner join `staffs` as `S` on `STHM`.`staff_id` = `S`.`staff_id` inner join `tasks` as `T` on `STHM`.`task_id` = `T`.`id`
)
) combined_tables
GROUP BY staff_name, task_type, task_desc
ORDER BY staff_name, task_type, task_desc;
Difficult for me to test, but try:
// Build up the sub-queries
$sub1 = DB::table('staff_task_history_calibrate AS STHC')
->select(DB::raw(
'CONCAT(S.first_name," ",S.last_name) as staff_name',
'STHC'.'task_id', 'IFNULL(T.type, "-") as task_type',
'T'.'description' as 'task_desc', 'STHC.task_multiplier')
)->join('staffs AS S', 'STHC.staff_id', '=', 'S.staff_id')
->join('tasks AS T', 'STHC.task_id', '=', 'T.id');
$sub2 = DB::table('staff_task_history_samples AS STHS')
->select(DB::raw(
'CONCAT(S.first_name," ",S.last_name) as staff_name',
'STHS'.'task_id', 'IFNULL(T.type, "-") as task_type',
'T'.'description' as 'task_desc', 'STHS.task_multiplier')
)->join('staffs AS S', 'STHS.staff_id', '=', 'S.staff_id')
->join('tasks AS T', 'STHS.task_id', '=', 'T.id');
$sub3 = DB::table('staff_task_history_measures AS STHM')
->select(DB::raw(
'CONCAT(S.first_name," ",S.last_name) as staff_name',
'STHM'.'task_id', 'IFNULL(T.type, "-") as task_type',
'T'.'description' as 'task_desc', 'STHM.task_multiplier')
)->join('staffs AS S', 'STHM.staff_id', '=', 'S.staff_id')
->join('tasks AS T', 'STHM.task_id', '=', 'T.id');
// Add the unions
$allUnions = $sub1->union($sub2)->union($sub3); // (Check the documentation for Unions in Query Builder)
// Get the results
$results = DB::table(DB::raw("({$allUnions->toSql()}) as combined_tables"))
->select('staff_name, task_id, task_type, task_desc')
->sum('task_multiplier')
->mergeBindings($allUnions) // We need to retrieve the underlying SQL
->groupBy('staff_name')
->groupBy('task_type')
->groupBy('task_desc')
->orderBy('staff_name')
->orderBy('task_type')
->orderBy('task_desc')
->get();
(If what you have works, I'd keep it.)

How to translate Fluent to Eloquent in Laravel

so i wanna try to get a filtering tag method, but in the database part is where i get lost, well kind of, because i wrote a raw query that works, but i need the Eloquent result so i can play with the relationships from the model class.
So here is the raw query:
$peticion = DB::select(DB::Raw("SELECT P.id, P.titulo, P.deadline, P.created_at, P.respuesta_id, U.usuario, C.titulo as categoria, C.clase_css as css, TG.Etiqueta
FROM peticiones P
JOIN usuarios U ON U.id = P.usuario_id
JOIN categorias C ON C.id = P.categoria_id
LEFT JOIN (
SELECT PT.peticion_id, T.nombre as Etiqueta
FROM tags T
JOIN peticion_tag PT ON PT.tag_id = T.id
) AS TG ON TG.peticion_id = P.id
JOIN (
SELECT PP.peticion_id
FROM (
SELECT PT.peticion_id, count(PT.peticion_id) AS conteo
FROM peticion_tag PT
WHERE PT.tag_id IN ( $etiquetas )
GROUP BY PT.peticion_id
) PP
WHERE PP.conteo = $len ) AS PPP
ON P.id = PPP.peticion_id
WHERE P.categoria_id = $id ;"));
what it does is that retrieve all the peticiones who has as many tags in it something like this in SO when filtering by tags.
But as i said i need the eloquent so this is my attempt to recreate the raw query:
$pet = Peticion::whereHas('tags', function($q) use ($tags, $len){
$q->whereIn('tag_id', $tags);
})
->where('categoria_id', '=', $id)
->get();
But it returns me all the peticiones who has this tag OR this tag, OR as many has the $tags array this get achieved with the raw query in the
WHERE PP.conteo = $len
but i dont know how to translate to eloquent.
Hope someone can help me, thanks a lot.

invalid use of group in mysql

I have the following query:
return $this->createQueryBuilder('s')
->select('DISTINCT s.username')
->addSelect('COUNT(p.id) as HIDDEN c_id')
->leftJoin('s.owner', 'o')
->leftJoin('s.userPictures', 'p')
->leftJoin('o.transactions', 't')
->leftJoin('t.packType', 'pt')
->where('pt.id =:packId')
->setParameter('packId', $packId)
->andWhere('s.expirydate >=:expiryDate')
->setParameter('expiryDate', new \DateTime('now'))
->andWhere('COUNT(p.id) <:numberOfPictures')
->setParameter('numberOfPictures', $numberOfPictures)
->groupBy('p.shop')
->orderBy("c_id", 'ASC')
->getQuery()
->getResult()
;
however when trying to run this I always get invalid use of group function. Why is this?
Here's the real SQL query when translated:
SELECT DISTINCT s.username, COUNT(p.id) as HIDDEN c_id
FROM App\MainBundle\Entity\InstagramShop s
LEFT JOIN s.owner o
LEFT JOIN s.userPictures p
LEFT JOIN o.transactions t
LEFT JOIN t.packType pt
WHERE pt.id =:packId AND s.expirydate >=:expiryDate AND COUNT(p.id) <:numberOfPictures
GROUP BY p.shop
ORDER BY c_id ASC