How to build conditional eloquent query with data which comes from database - laravel

I want to create conditional query with data which comes from database. Now im using query and filtering method but i wonder is there any method to build query for this?
Example:
I have a table which exists 2 columns -> user_id and view_preference
if view_preference is 0 i want to select all records. But if its 1 i just want to select only matching user_id rows.
Current Working Code:

You want something like this then.
WHERE view_preference = 0
OR (
view_preference = 1
AND (
owner_id = ?
OR supervisor_id = ?
)
)
Appending this to your query builder (before calling get()) should give you the results you want.
->where('view_preference', 0)
->orWhere(function ($or) use ($request) {
$or->where('view_preference', 1)
->where(function ($and) use ($request) {
$and->where('owner_id', $request->user()->id)
->orWhere('supervisor_id', $request->user()->id);
});
})

Related

Eloquent count occurrence with where clause

I'm trying to do a simple query using Eloquent. My test_registrants table looks like this
I want to add new column with value of all user_id with payment_status = 1
This is my query using whereColumn
TestRegistrant::select(['test_registrants.*'])
->where('payment_status', 1)
->addSelect([
'attempt' => TestRegistrant::select(DB::raw('count(*) as attempt'))
->whereColumn('test_registrants.user_id', 'user_id')
->where(function ($query) {
$query->where('payment_status', 1);
})
]);
but I get all user_id instead
What I'm trying to achieve is this one
So what do I do wrong here? thank you
The reason your query is returning 3, is because it is simply counting all the records that have payment_status = 1. The whereColumn() is not working properly, because it does not reflect the right columns.
When you define an alias for the user_id column on the test_registrants table, it should work. For example, you could name it: outer_user_id. I have updated your example accordingly:
TestRegistrant::select(['test_registrants.payment_status', 'test_registrants.user_id as outer_user_id'])
->where('payment_status', 1)
->addSelect([
'attempt' => TestRegistrant::selectRaw('count(*) as attempt')
->whereColumn('test_registrants.user_id', 'outer_user_id')
->where(function ($query) {
$query->where('payment_status', 1);
})
])
->get();
Alternatively, you could also look into grouping the results, so that you can count all the rows in a specific group.

How to avoid duplicated rows from my result array when using where clause

I need the names of the users that applied both the time I sent from my controller and time = double, so I need to display the results from this function but it duplicates the results, is there a way to resolve this?
The names of the users that picked time=double at a specific day, displays on everyday.
public function get_Shifts($day,$time){
$this->db->select('user.fullname');
$this->db->from('shifts');
$this->db->join('user', 'shifts.user_id = user.id', 'left');
$this->db->where('day=', $day);
$this->db->where('time=',$time);
$this->db->or_where('time=', $double);
$query = $this->db->get();
return $query->result_array();
}
I tried adding this line and it didn't help: $this->db->distinct();
Since Codeigniter 3 you can use it's Query Grouping functions:
Query grouping allows you to create groups of WHERE clauses by
enclosing them in parentheses. This will allow you to create queries
with complex WHERE clauses
In your case, you can use:
$this->db->group_start()
$this->db->where('day', $day);
$this->db->where('time', $time);
$this->db->group_end()
$this->db->or_where('time', $double);
this will generate something like:
WHERE ( (`day` = '2020-04-23' AND `time` = '16:00' ) OR `time` = true )
edit to respond to comment: to create an output like: WHERE ( (day = '2020-04-23' AND (time = '16:00' OR time = true ) )
you use this approach:
$this->db->where('day', $day);
$this->db->group_start()
$this->db->where('time', $time);
$this->db->or_where('time', $double);
$this->db->group_end()
note: the correct way to use CI where() function is:
$this->db->where('day', $day); and not $this->db->where('day=', $day);
There should be an error while using
$this->db->where('day=', $day);
$this->db->where('time=',$time);
$this->db->or_where('time=', $double);
The right way to use where clause
$this->db->where('day', $day);
$this->db->where('time',$time);
$this->db->or_where('time', $double);
And if you are getting duplicate data for the above query, pass column name to the distinct like :-
$this->db->distinct('user.fullname');

Eloquent query with a RAW order by

I have a eloquent query to get list items.
This is based on the idea that the sort column would be filled in, but in some circumstances it is not.
If its the case then I would like to order by the name of the list.
More or less what I wrote bellow.
order by CASE WHEN trickysort IS NOT NULL THEN trickysort::text ELSE list_name END
Here is the original query.
$list = Table_Lists::with(["listItems" =>
function($query)
{
$query
->orderBy('trickysort', 'asc')
->with("sublist.listItems");
}
])
->where("list_name","=", $name)
->where("hos_id","=", $hos_id)->get()->first();
return $list ? $list->toArray() : null;
The table structure is as follows.
Parent table -> table_lists
related child table -> table_list_items
the child table items are the one I need sorting. ( trickysort else list_name )
I hope this makes sense.
Im was thinking kind of a RAW query bit in the ->orderBy section of the child table.

Querying related table data with Eloquent

i have a problem trying to get records from a model based on a related table.
I have two tables one called leads and one called recycle_logs, my app will basically send the same record in the leads table like once a month, and when it does so i'll store a new record in recycle_logs.
The problem is that i need to select all leads with a specific campaign_id value and that have a specific status that is different from invalid, so far so good, now the problem is i need to get them only if they don't have any recycleLogs associated with them OR if the last recycleLog associated with that particular lead is older than 30 days ago for instance.
What i currently have looks somewhat like this.
$leads = $this->leadModel->where(Lead::CAMPAIGN_ID, $this->campaignID)
->where(Lead::DUPLICATED, Lead::DUPLICATED_NO)
->where(Lead::LEAD_STATUS, "!=" ,Lead::LEAD_STATUS_INVALID)
->orderBy(Lead::CREATED_AT, 'desc')
->with(
['leadRecyclingLog' => function($query) {
$query->where(LeadRecyclingLog::CREATED_AT, '<', (new Carbon())->subDays($this->configRecyclingDays))
->orWhere(LeadRecyclingLog::ID, null);
}]
)
->get();
What exactly am i doing wrong? It always selects the same number of records regardless of me adding or removing recycleLogs
I've managed to get it done through a raw SQL query which i'll post below in case it helps anyone, i'd still like to know how to do it in Eloquent/Query Builder.
SELECT * FROM `leads` LEFT JOIN `lead_recycling_logs` ON `leads`.`guid` = `lead_recycling_logs`.`original_lead_guid` WHERE `leads`.`campaign_id` = :campaignID AND `leads`.`duplicated` = 0 AND `leads`.`lead_status` != :invalidStatus AND (`lead_recycling_logs`.`id` IS NULL OR `lead_recycling_logs`.`created_at` < :recyclingDate) ORDER BY `leads`.`created_at` DESC
Try this:
$leads = $this->leadModel->where(Lead::CAMPAIGN_ID, $this->campaignID)
->where(Lead::DUPLICATED, Lead::DUPLICATED_NO)
->where(Lead::LEAD_STATUS, "!=" ,Lead::LEAD_STATUS_INVALID)
->orderBy(Lead::CREATED_AT, 'desc')
->where(function($q) {
$q->whereHas('leadRecyclingLog', function($q) {
$q->where(LeadRecyclingLog::CREATED_AT, '<', (new Carbon())->subDays($this->configRecyclingDays));
})
->orWhereHas('leadRecyclingLog', '<', 1); // Where count of the relationship is smaller than 1
})->get();
I assumed the first part of the query is working well (up until the relationship).
What you're looking for is ->whereHas(relationship), not ->with(relationship). ->with(relationship) will attach the associated results to the original model (the query for the original model will not be affected by ->with()). ->whereHas(relationship) filters the original model by the condition.
Got it to work through #devk 's help
$leads = $this->leadModel->where(Lead::CAMPAIGN_ID, $this->campaignID)
->where(Lead::DUPLICATED, Lead::DUPLICATED_NO)
->where(Lead::LEAD_STATUS, "!=" ,Lead::LEAD_STATUS_INVALID)
->orderBy(Lead::CREATED_AT, 'desc')
->where(function($q) {
$q->whereHas('leadRecyclingLog', function($q) {
$q->where(LeadRecyclingLog::CREATED_AT, '<', (new Carbon())->subDays($this->configRecyclingDays));
})
->doesntHave('leadRecyclingLog', 'or');
})->get();

Laravel WhereIn or Wheren with where

Im trying to design a query, but I have no idea where to start.
I'll type it out how I want it to function.
Items::whereIn('id',$ids)->orWhereIn('id_2',$ids)->where('type','!=',$type)->get();
Thats how I want it to work, but I know that wont work, because it will just ignore the WHERE type=$type query, because the whereIN's would have already pulled records, that dont adhere to the Where query.
Basically I want the eloquent version of this...
"SELECT * FROM items WHERE type!=$type AND (id IN (1,2,3) OR id_2 IN(1,2,3))"
What you are attempting to do is to group statements: https://laravel.com/docs/5.3/queries#parameter-grouping
What you need to do is to make the code something like this:
Items::where('type', '!=', $type)
->where(function ($query) use ($ids) {
$query->whereIn('id',$ids)
->orWhereIn('id_2',$ids);
})
->get();
That way you are grouping the where in clauses.
$user_id = 2 ;
$user_ids = [2,3,4,5,6,7,78,87,88,90] ;
where('id',$user_id) vs whereIn('id',$user_ids)
Note: where will compare with just first value of array or just one single value. and whereIn will compare evey index of array.
You're gonna want to do something like this:
Item::where('type','!=','ATypeTest')->where(function ($query) {
$query->whereIn('id',[1, 2, 3])->orWhereIn('id_2',[1, 2, 3]);
})->get();
Check the Laravel documentation on more regarding grouping: https://laravel.com/docs/5.3/queries#parameter-grouping
This will by the way generate the following SQL query:
SELECT * FROM "items" WHERE "type" != `ATypeTest` AND ("id" in (1, 2, 3) OR "id_2" in (1, 2, 3))

Resources