Laravel morphedByMany return all records by where condition and count - laravel

Table 1: products: id, title, publish,created_at
Table 2: tags: id,name,created_at
Table 3: taggable: id,tag_id,taggable_type,taggable_id
I want get all distinct tags with count order by name.
I want it to return an array like this:
[
['name1'=>'value1','count'=>3],
['name2'=>'value2','count'=>3]
]
I have tried to do it like this:
$tags = \App\Tag::distinct()->where( function( $query ){
$query->whereHas('products', function ( $subquery ){
$subquery->where('publish', 1 );
})->get()->toarray();
})->withCount('products')->get()->toarray();
but it returns all (product) tags and all products_count values are 1 like this:
[...],
[▼
"id" => 75
"name" => "test1"
"created_at" => "2018-10-30 18:49:51"
"products_count" => 1
],
[...]
...
EDIT:
SELECT DISTINCT `tags`.*,
(SELECT count(*)
FROM `products`
INNER JOIN `taggables` ON `products`.`id` = `taggables`.`taggable_id`
WHERE `tags`.`id` = `taggables`.`tag_id`
AND `taggables`.`taggable_type` = ?) AS `products_count`
FROM `tags`
WHERE (EXISTS
(SELECT *
FROM `products`
INNER JOIN `taggables` ON `products`.`id` =`taggables`.`taggable_id`
WHERE `tags`.`id` = `taggables`.`tag_id`
AND `taggables`.`taggable_type` = ?
AND `publish` = ?))

withCount('products') must be called first and distinct() must be the last before ->get()->toArray().
Try this (not tested though):
$tags = \App\Tag::withCount('products')->where( function( $query ){
$query->whereHas('products', function ( $subquery ){
$subquery->where('publish', 1 );
})->get()->toArray();
})->distinct()->get()->toArray();

Related

Raw Laravel query as a collection with conditions

I've got a fairly complex query that I'd rather not write in Eloquent so I've written it raw. The only problem is that I need to be able to search/filter through the data using the front-end this query is connected to.
This what I've tried but I'm getting an "Call to a member function get() on null" error.
Here's my code:
$report = collect(DB::connection('mysql2')->select("SELECT
t2.holder,
t2.merchantTransactionId,
t2.bin,
t2.last4Digits,
t3.expDate,
(CASE WHEN t3.expDate < CURDATE() THEN 'Expired'
WHEN t3.expDate > CURDATE() THEN 'Due to expire' END) AS expInfo,
t2.uuid
FROM transactions AS t2
INNER JOIN (
SELECT t1.uuid, t1.holder, t1.bin, t1.last4Digits, LAST_DAY(CONCAT(t1.expiryYear, t1.expiryMonth, '01')) AS expDate
FROM transactions t1
JOIN (SELECT t1.merchant_access
FROM total_control.users,
JSON_TABLE(merchant_access, '$[*]' COLUMNS (
merchant_access VARCHAR(32) PATH '$')
) t1
WHERE users.id = :userId
) AS t2
ON t1.merchantUuid = t2.merchant_access
WHERE t1.paymentType = 'RG'
AND t1.status = 1
) t3
ON t2.uuid = t3.uuid
WHERE t3.expDate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND DATE_ADD(CURDATE(), INTERVAL 30 DAY)
GROUP BY t2.holder, t2.bin, t2.last4Digits
ORDER BY t2.holder ASC", ['userId' => $request->userId]))
->when($request->search['holder'], function($q) use ($request) {
$q->where('t2.holder', 'LIKE', '%'.$request->search['holder'].'%');
})->get();
return $report;

subquery inside orWhere in laravel

I need assistance to build up the query like below in laravel:
SELECT *
FROM table t
WHERE t.a = 1
OR (t.a=0
AND t.id IN (
SELECT o.a_id
FROM other_table o
WHERE o.x > 3
)
);
You could try to build your exact current query, and in fact it might even be the most efficient to write it. But, if we rephrase your query using a left join, it becomes somewhat easier to express in Laravel code.
SELECT *
FROM your_table t
LEFT JOIN other_table o
ON t.id = o.a_id AND o.x > 3
WHERE
t.a = 1 OR
(t.a = 0 AND o.a_id IS NOT NULL);
This would translate to the following Laravel code:
$result = DB::table('your_table t')
->leftJoin('other_table o', function($join) {
$join->on('t.id', '=', 'o.a_id');
$join->on('o.x', '>', '3');
})
->where('t.a', '=', '1')
->orWhere(function($query) {
return $query->where('t.a', '=', '0')
->whereNotNull('o.a_id')
})
->get();

cake php distinct date_format

Please I need some help with cakephp3 mysql distinct.
My desire result in SQL:
select distinct(date_format(torokuDate,'%Y')) as year
from kani_tbl
where torokuDate >= '2000-01-01'
order by torokuDate ASC
limit 1;
But I get the wrong result:
SELECT (date_format((torokuDate), '%Y')) AS `year`
FROM kani_tbl
WHERE torokuDate > :c0
GROUP BY torokuDate
ORDER BY torokuDate ASC
LIMIT 1
My model src:
$query = $this->find();
$time = $query->func()->date_format([
'torokuDate' => 'identifier',
"'%Y'" => 'literal'
]);
$yearList = $query->select(['year' => $time])
->distinct('torokuDate')
->from('kani_tbl ')
->order(['torokuDate' => 'ASC'])
->where(['torokuDate >' => '2000-01-01'])
->limit(1);
// ->hydrate(false)
// ->toArray();
var_dump($yearList);
Please help me to add distinct field in the MySQL command.
As your expected query, you need to distinct result of date_format(torokuDate, '%Y'), not the 'torokuDate' field. So your code should be like this:
$yearList = $query->select(['year' => $time])
->distinct()
->from('kani_tbl ')
->order(['torokuDate' => 'ASC'])
->where(['torokuDate >' => '2000-01-01'])
->limit(1);
How to use distinct method: https://api.cakephp.org/3.4/class-Cake.Database.Query.html#_distinct

laravel query builder from normal query

DB::select(DB::raw( 'SELECT a.bill_no, a.account_id, a.bill_date, a.amount_paid,
b.transaction_code,b.amount from bill_det a left join
(select bill_no, transaction_code, sum(amount) as amount from payment_transactions
where status = "success" group by bill_no ) b
on a.bill_no = b.bill_no where a.amount_paid != b.amount order by b.bill_no'));
this is normal query.change into laravel query?.
i tried.
$bill=DB::table('bill_det')->leftJoin('payment_transactions', 'bill_det.bill_no', '=', 'payment_transactions.bill_no')
->select('bill_det.bill_no','bill_det.account_id','bill_det.bill_date','bill_det.amount_paid',
'payment_transactions.transaction_code',DB::raw('sum(payment_transactions.amount) as amount'))
->where('payment_transactions.status','=','success')
->where('sum(payment_transactions.amount)','!=',DB::raw('bill_det.amount_paid'))
->groupBy('bill_det.bill_no')
->orderBy('bill_det.bill_no','desc');
i can't compare -> where('sum(payment_transactions.amount)','!=',DB::raw('bill_det.amount_paid'))
i used like this ->whereRaw('bill_det.amount_paid != sum(payment_transactions.amount)')
{"error":{"type":"Illuminate\Database\QueryException","message":"SQLSTATE[HY000]: General error: 1111 Invalid use of group function (SQL: select count(*) as aggregate from (select '1' as row_count from bill_det left join payment_transactions on bill_det.bill_no = payment_transactions.bill_no where payment_transactions.status = success and bill_det.amount_paid != sum(payment_transactions.amount) group by bill_det.bill_no order by bill_det.bill_no desc) count_row_table)"
DB::select(DB::raw( 'SELECT a.bill_no, a.account_id, a.bill_date, a.amount_paid,
b.transaction_code,b.amount from bill_det a left join
(select bill_no, transaction_code, sum(amount) as amount from payment_transactions
where status = "success" group by bill_no ) b
on a.bill_no = b.bill_no where a.amount_paid != b.amount order by b.bill_no'));
After converting this to laravel Query::
$query = \Illuminate\Support\Facades\DB::table('bill_det')
->select('a.bill_no', 'a.account_id', 'a.bill_date', 'a.amount_paid', 'b.transaction_code', 'b.amount')
->leftJoin(DB::raw('(select bill_no, transaction_code, sum(amount) as amount from payment_transactions
where status = "success" group by bill_no) b'), function($join) {
$join->on('a.bill_no', '=', 'b.bill_no');
})
->where('a.amount_paid','<>', 'b.amount')
->orderBy('b.bill_no')
->get();
In case you want to know how to use raw expression inside where then use this:
$query->whereRaw(DB::raw('(your expression!!)'));

left join with ActiveRecord (yii2)

I tried to send SQL request with LEFT JOIN but it doesn't display data from table2 table.
public static function top($limit)
{
return self::findBySql("
SELECT * FROM table 1 g1
LEFT JOIN table2 s1
ON (g1.id = s1.g_id AND s1.id = (
SELECT MAX(id)
FROM table2 s2 WHERE s2.g_id = g1.id
))
LIMIT :limit",
[':limit' => $limit]
)->all();
}
It seems you are adding this function to the model and self represents the model itself.
Yii will not return results from another table and will be limited to the model only if you are calling the find on a model, instead you need to use a db query as below:
$query = new \yii\db\Query;
$query->select('*')
->from('table 1 g1')
->leftJoin('table2 s1', 's1.g_id AND s1.id = (SELECT MAX(id) FROM table2 s2 WHERE s2.g_id = g1.id')
->limit($Limit);
$command = $query->createCommand();
$resp = $command->queryAll();
The correct SQL query is
SELECT * FROM table 1 g1
LEFT JOIN table2 s1
ON g1.some_field = s1.some_field
where g1.some_field = s1.some_field are the fields that define the join.
I have working code something like...:)
with user and user_friend_list
$query = new Query;
$query ->select(['user.id AS user_id', 'user_friend_list.id'])
->from('user')
->innerJoin('user_friend_list', 'user.email = user_friend_list.email');
$command = $query->createCommand();
$data = $command->queryAll();
foreach($data as $datakey)
{
//echo $datakey['id'];
$friendfind = UserFriendList::findOne($datakey['id']);
$friendfind->is_app_using_user_id=$datakey['user_id'];
$friendfind->save();
}

Resources