Laravel eloquent difficult relation query - php

I'm a system for a friend, but stumbled across a little problem.
I've got 3 models (customerCard, customerCardComment and customerCardFollowup).
It's better if you see the image below to understand what I'm trying to achieve. As you see I'm trying to get a result where I get a customerCard model where the sold field is equal to 0 and the customerCard model has no customerCardComment model where the type field is equal to 1,2 or 3, and the customerCard also does not have any customerCardFollowup.
Databases:
customer_cards
customer_card_comments
customer_card_followups
Both comments and followups table are related to the ID field in customer_cards. Both have foreign keys customer_card_id.
Is there a way to do this query? Or am i lost?
Thanks in advance.

Laravel's whereHas accepts a 3rd and 4th parameter. The 3rd parameter is the comparison operator against the count of the result set, and the 4th argument is the number to compare against. This will solve the first problem:
CustomerCard::where(function($query){
$query->where('sold', 0)
->whereHas('customerCardComment', function($query){
return $query->whereIn('type', [1,2,3]);
}, '=', 0);
});
Next, you can use ->has() to count the number of records returned from a relation, this will solve your second problem:
CustomerCard::where(function($query){
$query->where('sold', 0)
->whereHas('customerCardComment', function($query){
return $query->whereIn('type', [1,2,3]);
}, '=', 0)
->has('customerCardFollowup', '=', 0);
});
The 3rd one is actually a bit more complex and I need to think about how to approach that a bit more. I'll answer now to get you going in the right direction and edit and update the post with the solution to the 3rd problem shortly.

Related

How to achieve sub collection on a collection of an array?

I want to get the detailed product of a collection from groupBy in laravel. How can I achieve that?
I'm using php 7.1 and Laravel. I can get the collection for the total report for year, month, and day.
But can I get detailed product of that collection ?
My query for getting the collection in the controller
$totalBelanjaTahun = DB::table('assets')
->select(DB::raw('EXTRACT(MONTH FROM belitanggal_assets) AS monthCoba, SUM(beliharga_assets) AS harga_beli'))
->where('belitanggal_assets', 'like', '%'.$tahun.'%')
->groupBy(DB::raw('monthCoba'))
->get();
return view('DilarangBuka.reportTotalBelanjaTahun', compact('totalBelanjaTahun', 'tahun', 'totalPertahun'));
How can I achieve get detailed of product of that array, not just get the date and the price? Thanks
Don't groupBy records in mysql, you will get first record of every groups.
Try to get them out.
$totalBelanjaTahun = DB::table('assets')
->select(DB::raw('EXTRACT(MONTH FROM belitanggal_assets) AS monthCoba, beliharga_assets AS harga_beli, field1, field2, field3'))
->where('belitanggal_assets', 'like', '%'.$tahun.'%')
->get();
And groups them by collect
collect($totalBelanjaTahun)->groupBy('monthCoba')
Hope this can help you.

How can I retrieve the information I want using MySQL `joins` or Laravel `relationships`?

I am working on a project using the Laravel framework. In this project I have three tables:
1) Master Part Numbers (master_part_numbers)
Columns: id, part_number
Values: 1, MS26778-042
2) Inventory (inventory)
Columns: id, master_part_number, stock_qty
Values: 1, 1, 7
3) Inventory Min Maxes (inventory_min_maxes)
Columns: id, master_part_number, min_qty
Values: 1, 1, 10
I am trying to find the inventory where the stock level is below the min_qty. I have been attempting this using joins, like so:
$test = MasterPartNumber::table('master_part_numbers')
->join('inventory', 'master_part_numbers.id', '=', 'inventory.master_part_number_id')
->join('inventory_min_maxes', 'master_part_numbers.id', '=', 'inventory_min_maxes.master_part_number_id')
->select('master_part_numbers.part_number')
->where('inventory.stock_qty', '<=', 'inventory_min_maxes.min_qty')
->get();
However I am getting an empty collection every time. I have tried removing the where() clause and I get all the part numbers in the inventory, so it feels like I'm on the right track, but missing a critical component.
Also, I don't know if there is an easier or more efficient way to do this using Laravel's Eloquent Relationships, but that option is available.
Note: I added the space after table('master_part_numbers') in my query displayed here on purpose, for readability.
EDIT 1:
This sql query returns the expect result:
SELECT master_part_numbers.part_number
FROM master_part_numbers
JOIN inventory ON master_part_numbers.id=inventory.master_part_number_id
JOIN inventory_min_maxes ON master_part_numbers.id=inventory_min_maxes.master_part_number_id
WHERE inventory.stock_qty<=inventory_min_maxes.min_qty;
EDIT 2:
I finally got it working with some help from the Laravel IRC, however it isn't ideal because I am missing out on some of the data I would like to display, normally collected through relationships.
Here is what I am currently using, but I hope to get refactored:
DB::select(DB::raw('SELECT master_part_numbers.id, master_part_numbers.part_number, master_part_numbers.description, inventory.stock_qty, inventory.base_location_id, inventory_min_maxes.min_qty, inventory_min_maxes.max_qty
FROM master_part_numbers
JOIN inventory ON master_part_numbers.id = inventory.master_part_number_id
JOIN inventory_min_maxes ON master_part_numbers.id = inventory_min_maxes.master_part_number_id
WHERE inventory.stock_qty <= inventory_min_maxes.min_qty'));
If I have understood your problem correctly then
'masters_part_numbers.id' == 'inventory.id' and
'inventory.master_part_number' == 'inventory_min_maxes.master_part_number'
$test = DB::table('master_part_numbers')
->join('inventory', 'master_part_numbers.id', '=', 'inventory.id')
->join('inventory_min_maxes', 'inventory.master_part_number', '=', 'inventory_min_maxes.master_part_number')
->where('inventory.stock_qty', '<=', 'inventory_min_maxes.min_qty')
->whereNotNull('inventory_min_maxes.master_part_number');
->select(DB::raw('part_number'))
->get();
Based on above criteria. This code will work. I tried in laravel 5.4 .
Try and let me know. nd if it work give me a thumbs up
I discovered a way to solve this problem using the Laravel ->whereRAW() statement:
$test = $inventory->join('inventory_min_maxes', 'inventory.id', '=', 'inventory.inventory_min_max_id')
->whereRaw('inventory.stock_qty <= inventory_min_maxes.min_qty')
->whereRaw('inventory.inventory_min_max_id = inventory_min_maxes.id') // required so it tests against the specific record, without it will test against all records.
->get();
The major advantage for me, other than it looked terribly ugly before, was that I can now use the power of relationships.
Note: $inventory is an instance of my Inventory model, which I type hinted in the index() method.

laravel query php how to get max value within a range

hello how do i get the max value of scores, where column ID range starts at 3-5
example table
I want to get the max value of scores, where column ID ranging from 3-5
, please help,
what I have done so far:
$max_scores_table= DB::table('scores_table')
->where('id', '>', 2)
->max('score');
another problem is when i have a decimal points in the table
when I used the max() function it gets the ID=5, which has a Score of 4.5, instead of ID=4 with a value of 4.6, tnx in advance
Try to use whereBetween hope this works:
$max_scores_table= DB::table('scores_table')
->select(DB::raw('MAX(score) FROM scores_table as MaxScore'))
->whereBetween('id', array(3,5))
->where('score', 'MaxScore')
->get();
OR:
$max_scores_table= DB::table('scores_table')
->whereBetween('id', array(3,5))
->max('score')
->get();
Write query as below:
$max_scores_table = DB::table('scores_table')
->whereBetween('id',array(3,5))
->max('score');
Reference: Laravel API
Use query like this
$max_scores_table = DB::table('scores_table')
->whereBetween('id', array(3, 5))->max('score')->get();
For your reference just follow Laravel Documentation

Laravel - Eloquent or Fluent random row

How can I select a random row using Eloquent or Fluent in Laravel framework?
I know that by using SQL, you can do order by RAND(). However, I would like to get the random row without doing a count on the number of records prior to the initial query.
Any ideas?
Laravel >= 5.2:
User::inRandomOrder()->get();
or to get the specific number of records
// 5 indicates the number of records
User::inRandomOrder()->limit(5)->get();
// get one random record
User::inRandomOrder()->first();
or using the random method for collections:
User::all()->random();
User::all()->random(10); // The amount of items you wish to receive
Laravel 4.2.7 - 5.1:
User::orderByRaw("RAND()")->get();
Laravel 4.0 - 4.2.6:
User::orderBy(DB::raw('RAND()'))->get();
Laravel 3:
User::order_by(DB::raw('RAND()'))->get();
Check this article on MySQL random rows. Laravel 5.2 supports this, for older version, there is no better solution then using RAW Queries.
edit 1: As mentioned by Double Gras, orderBy() doesn't allow anything else then ASC or DESC since this change. I updated my answer accordingly.
edit 2: Laravel 5.2 finally implements a wrapper function for this. It's called inRandomOrder().
This works just fine,
$model=Model::all()->random(1)->first();
you can also change argument in random function to get more than one record.
Note: not recommended if you have huge data as this will fetch all rows first and then returns random value.
tl;dr: It's nowadays implemented into Laravel, see "edit 3" below.
Sadly, as of today there are some caveats with the ->orderBy(DB::raw('RAND()')) proposed solution:
It isn't DB-agnostic. e.g. SQLite and PostgreSQL use RANDOM()
Even worse, this solution isn't applicable anymore since this change:
$direction = strtolower($direction) == 'asc' ? 'asc' : 'desc';
edit: Now you can use the orderByRaw() method: ->orderByRaw('RAND()'). However this is still not DB-agnostic.
FWIW, CodeIgniter implements a special RANDOM sorting direction, which is replaced with the correct grammar when building query. Also it seems to be fairly easy to implement. Looks like we have a candidate for improving Laravel :)
update: here is the issue about this on GitHub, and my pending pull request.
edit 2: Let's cut the chase. Since Laravel 5.1.18 you can add macros to the query builder:
use Illuminate\Database\Query\Builder;
Builder::macro('orderByRandom', function () {
$randomFunctions = [
'mysql' => 'RAND()',
'pgsql' => 'RANDOM()',
'sqlite' => 'RANDOM()',
'sqlsrv' => 'NEWID()',
];
$driver = $this->getConnection()->getDriverName();
return $this->orderByRaw($randomFunctions[$driver]);
});
Usage:
User::where('active', 1)->orderByRandom()->limit(10)->get();
DB::table('users')->where('active', 1)->orderByRandom()->limit(10)->get();
edit 3: Finally! Since Laravel 5.2.33 (changelog, PR #13642) you can use the native method inRandomOrder():
User::where('active', 1)->inRandomOrder()->limit(10)->get();
DB::table('users')->where('active', 1)->inRandomOrder()->limit(10)->get();
You can use:
ModelName::inRandomOrder()->first();
it's very simple just check your laravel version
Laravel >= 5.2:
User::inRandomOrder()->get();
//or to get the specific number of records
// 5 indicates the number of records
User::inRandomOrder()->limit(5)->get();
// get one random record
User::inRandomOrder()->first();
or using the random method for collections:
User::all()->random();
User::all()->random(10); // The amount of items you wish to receive
Laravel 4.2.7 - 5.1:
User::orderByRaw("RAND()")->get();
Laravel 4.0 - 4.2.6:
User::orderBy(DB::raw('RAND()'))->get();
Laravel 3:
User::order_by(DB::raw('RAND()'))->get();
In Laravel 4 and 5 the order_by is replaced by orderBy
So, it should be:
User::orderBy(DB::raw('RAND()'))->get();
For Laravel 5.2 >=
use the Eloquent method:
inRandomOrder()
The inRandomOrder method may be used to sort the query results randomly. For example, you may use this method to fetch a random user:
$randomUser = DB::table('users')
->inRandomOrder()
->first();
from docs: https://laravel.com/docs/5.2/queries#ordering-grouping-limit-and-offset
You can also use order_by method with fluent and eloquent like as:
Posts::where_status(1)->order_by(DB::raw(''),DB::raw('RAND()'));
This is a little bit weird usage, but works.
Edit: As #Alex said, this usage is cleaner and also works:
Posts::where_status(1)->order_by(DB::raw('RAND()'));
Use Laravel function
ModelName::inRandomOrder()->first();
You can easily Use this command:
// Question : name of Model
// take 10 rows from DB In shuffle records...
$questions = Question::orderByRaw('RAND()')->take(10)->get();
There is also whereRaw('RAND()') which does the same, you can then chain ->get() or ->first() or even go crazy and add ->paginate(int).
I prefer to specify first or fail:
$collection = YourModelName::inRandomOrder()
->firstOrFail();
Laravel has a built-in method to shuffle the order of the results.
Here is a quote from the documentation:
shuffle()
The shuffle method randomly shuffles the items in the collection:
$collection = collect([1, 2, 3, 4, 5]);
$shuffled = $collection->shuffle();
$shuffled->all();
// [3, 2, 5, 1, 4] - (generated randomly)
You can see the documentation here.
At your model add this:
public function scopeRandomize($query, $limit = 3, $exclude = [])
{
$query = $query->whereRaw('RAND()<(SELECT ((?/COUNT(*))*10) FROM `products`)', [$limit])->orderByRaw('RAND()')->limit($limit);
if (!empty($exclude)) {
$query = $query->whereNotIn('id', $exclude);
}
return $query;
}
then at route/controller
$data = YourModel::randomize(8)->get();
I have table with thousands of records, so I need something fast. This is my code for pseudo random row:
// count all rows with flag active = 1
$count = MyModel::where('active', '=', '1')->count();
// get random id
$random_id = rand(1, $count - 1);
// get first record after random id
$data = MyModel::where('active', '=', '1')->where('id', '>', $random_id)->take(1)->first();
Here's how I get random results in eloquent in one of my projects:
$products = Product::inRandomOrder()->limit(10);
10 - The number of random records to pull.
Try this code! It Works:
User::orderBy(DB::raw('RAND()'))->get();

Kohana orm order asc/desc?

I heed two variables storing the maximum id from a table, and the minimum id from the same table.
the first id is easy to be taken ,using find() and a query like
$first = Model::factory('product')->sale($sale_id)->find();
but how can i retrieve the last id? is there a sorting option in the Kohana 3 ORM?
thanks!
Yes, you can sort resulting rows in ORM with order_by($column, $order). For example, ->order_by('id', 'ASC').
Use QBuilder to get a specific values:
public function get_minmax()
{
return DB::select(array('MAX("id")', 'max_id'),array('MIN("id")', 'min_id'))
->from($this->_table_name)
->execute($this->_db);
}
The problem could actually be that you are setting order_by after find_all. You should put it before. People do tend to put it last.
This way it works.
$smthn = ORM::factory('smthn')
->where('something', '=', something)
->order_by('id', 'desc')
->find_all();
Doing like this, I suppose you'll be :
selecting all lines of your table that correspond to your condition
fetching all those lines from MySQL to PHP
to, finally, only work with one of those lines
Ideally, you should be doing an SQL query that uses the MAX() or the MIN() function -- a bit like this :
select max(your_column) as max_value
from your_table
where ...
Not sure how to do that with Kohana, but this topic on its forum looks interesting.

Categories