sql query for count the number which have same value - laravel

i have patients visit table, so i have to know how much the particular patient had visited hospital. i had used below query:
(select count(id) from visit where cid = cid) as vno.
so, i want to count the all same cid value. and display in 'vno' column . and one patient had only one cid. so if that particular patient had visit again and again. i need to know that how many time that particular patient had visited
and below i have image of visit page

I think its work
$noOfVisit = DB::table('visit')->whereCid($cid)->count();
dd($noOfVisit);

What about hasMany relationship for Patient model?
public function visits()
{
return $this->hasMany(Visit::class, 'cid', 'cid');
}
Then in your view
{{ $patient->visits->count() }}

$unique_visitors = Visit::pluck('cid')->unique()->toArray();
$visitor_count = [];
foreach($unique_visitors as $visitor_id)
{
$visitor_count[$visitor_id] = count(Visit::where('cid','=',$visitor_id)->get());
}
// output would be an array with key as cid and value as their visit counts
// Something like this
Array(
[1] => 13;
[2] => 6;
)

Related

Having trouble grouping columns in Linq query with multiple joins

I have an MVC ViewModel that I'd like to pass through to a Razor view. In the controller, I've created a database context and joined tables together using Linq. Once summed and grouped, I'm getting an error:
Error CS1061 'decimal' does not contain a definition for 'GroupBy' and no accessible extension method 'GroupBy' accepting a first argument of type 'decimal' could be found (are you missing a using directive or an assembly reference?
I've gone through almost every example on stack overflow and google and couldn't find an example that matched the structure of my query. Also, the MS examples are very trivial and are not of much use.
Here is the action in the controller:
public IHttpActionResult GetEmployeeReleasedAllocatedBonus(int eid)
{
var employeeReleasedAllocatedBonus =
(from br in _context.BonusReleases
join emp in _context.Employees
on new
{
br.EmployeeID,
empID = br.EmployeeID
} equals new
{
emp.EmployeeID,
empID = eid
}
join job in _context.Jobs on br.JobID equals job.JobID
join bonus in _context.Bonus
on new
{
br.JobID,
empID = br.EmployeeID
}
equals new
{
bonus.JobID,
empID = bonus.EmployeeID
}
select new EmployeeAllocatedReleasedBonusViewModel()
{
AllocatedToEmployee = br.Amount, AllocatedPercentage = bonus.Amount * 100
,
JobNumber = job.JobNumber, JobDescription = job.JobDescription
})
.ToList()
.Sum(s => s.AllocatedToEmployee)
.GroupBy(g => new {g.JobNumber, g.JobDescription, g.AllocatedPercentage});
return Ok(employeeReleasedAllocatedBonus);
}
It's worth mentioning that the AllocatedPercentage datatype is a decimal. However, I've tried changing it to string but the error message stays.
Also tried using the group functionality right before .ToList() but that didn't work either.
After ToList() you have a List<EmployeeAllocatedReleasedBonusViewModel>.
In Sum(s => s.AllocatedToEmployee), every s is one EmployeeAllocatedReleasedBonusViewModel. Apparently a EmployeeAllocatedReleasedBonusViewModel has a property AllocatedToEmployee which is probably of type decimal. This can be summed into one decimal.
The result of the Sum (a decimal) is the input of your GroupBy. Does type decimal have a method GroupBy? Of course it doesn't!
Alas you forgot to tell us your requirements. It is difficult to extract them from code that doesn't do what you want.
It seems to me that you have two one-to-many relations:
Employees have zero or more BonusReleases. Every BonusRelease belongs to exactly one Employee using foreign key
Jobs have zero or more BonusReleases. Every BonusRelease belongs to exactly one Job.
Now what do you want: do you want all JobNumbers and JobDescriptions of all Jobs with the total of their AllocatedPercentage? I'm not sure what the Employees do within this query.
Whenever you want items with their sub-items, like Schools with their Students, Customers with their Orders, Orders with their OrderLines, use GroupJoin. If you want it the other way round: Student with the School that he attends, Order with the Customer who placed the Order, use Join.
var result = dbContext.Jobs.GroupJoin(dbContext.BonusReleases,
job => job.Id, // from every Job take the primary key
bonusRelease => bonusReleas.JobId, // from every BonusRelease take the foreign key
// parameter ResultSelector: take every Job with all its BonusReleases to make a new:
(job, bonusReleasesOfThisJob) => new
{
JobNumber = job.JobNumber,
JobDescription = job.JobDescription
// do you want the total of all allocated percentages?
TotalAllocatedPercentages = bonusReleasesOfThisJob
.Select(bonus => bonus.Amount)
.Sum(),
// do something to make it a percentage
// or do you want a sequence of allocated percentages?
TotalAllocatedPercentages = bonusReleasesOfThisJob
.Select(bonus => bonus.Amount)
.ToList(),
});
Or do you want the JobNumber / JobDescription / Total allocated bonus per Employee?
var result = dbContext.Employees.GroupJoin(dbContext.BonusReleases,
employee => employee.Id, // from every Employee take the primary key
bonus => bonus.EmployeeId, // from every BonusRelease take the foreign key
(employee, bonusesOfThisEmployee) => new
{
// Employee properties:
EmployeeId = employee.Id,
EmpoyeeName = employee.Name,
// for the jobs: Join the bonusesOfThisEmployee with the Jobs:
Jobs = dbContext.Jobs.GroupJoin(bonusOfThisEmployee,
job => job.Id,
bonusOfThisEmployee => bonusOfThisEmployee.JobId,
(job, bonusesOfThisJob) => new
{
Number = job.Id,
Description = job.Description,
TotalBonus = bonusOfThisJob.Select(bonus => bonus.Amount).Sum(),
}),
});
Harald's comment was key - after ToList(), I had a list of . Therefore I took a step back and said what if I put the results into an anonymous object first. Then do the group by and then the sum, putting the final result into the view model. It worked. Here is the answer.
var employeeReleasedAllocatedBonus =
(from br in _context.BonusReleases
join emp in _context.Employees
on new
{
br.EmployeeID,
empID = br.EmployeeID
} equals new
{
emp.EmployeeID,
empID = eid
}
join job in _context.Jobs on br.JobID equals job.JobID
join bonus in _context.Bonus
on new
{
br.JobID,
empID = br.EmployeeID
}
equals new
{
bonus.JobID,
empID = bonus.EmployeeID
}
select new
{
AllocatedToEmployee = br.Amount
,AllocatedPercentage = bonus.Amount * 100
,JobNumber = job.JobNumber
,JobDescription = job.JobDescription
})
.GroupBy(g => new {g.JobNumber, g.JobDescription, g.AllocatedPercentage})
.Select(t => new EmployeeAllocatedReleasedBonusViewModel
{
JobNumber = t.Key.JobNumber,
JobDescription = t.Key.JobDescription,
AllocatedPercentage = t.Key.AllocatedPercentage,
AllocatedToEmployee = t.Sum(ae => ae.AllocatedToEmployee)
});

Sorting a field based on several values in Laravel

I have an array of city codes
$cities=[9,12,14,2,3,4,5,6,8,10,11,13]
My posts table has a foreign key named city_id
I want sorting posts based on the values of this array
In this way: the first posts of the city 9 then the posts of the city 12 and then posts of city 14 and etc to be loaded
I tried using this method but this is wrong
$posts->orderByRaw('city_id in ? desc',$cities);
Can you help me find the best solution?
The only way i can i think of doing something like that(at least right now) is by doing something like so
$all_posts = [];
$cities=[9,12,14,2,3,4,5,6,8,10,11,13];
foreach ($cities as city) {
$city_posts = Post::whereRaw('city_id = ?', $city)->orderByRaw('created_at DESC');
array_push($all_posts, $city_posts);
}
dd($all_posts);
1st find all the posts relevant to cities and then sort w.r.t given order like
$cities = [9,12,14,2,3,4,5,6,8,10,11,13]; // order you'd like to see with posts
$posts = Post::whereIn('city_id', $cities)->sort(function($a, $b) uses ($cities) {
$pos_a = array_search($a->getAttributes()['city_id'], $cities);
$pos_b = array_search($b->getAttributes()['city_id'], $cities);
return $pos_a - $pos_b;
})->get();
// $posts contains the required order with city_ids
You can use raw query with "CASE something THEN index" this way you tell the query to see something as index so you can assign 0 to the first item in your array.
$sql .= "....";
foreach($cities as $index => $city) {
$sql .= "CASE {$city} THEN {$index}";
}
$sql .= "....";
Thanks to the friends solution,I used this method, and I think it's less complicated than the suggested methods of friends
$posts=$posts->orderByRaw('FIELD(city_id, '.$cities->implode( ', ').') asc')->orderBy('created_at','desc')->get();

Multiple array manipulations and merging

I am an amateur programmer that needs the help of a real one to resolve this beautiful problem, because I must admit that I am really stuck on this one!
In my database I have a « tslines » table that contains a value (sum_week) for a given week(startdate) and a given contract(contract_id)
The fields that are important are : sum_week, user_id , startdate and contract_id
I also have a « users » table, the important values are « first_name, last_name »
I have many workers that have worked on a contract, at different times (startdate, represents the first day of the week)
Example (table below): I can have 3 lines for worker A, and 2 lines for worker B
For some week(startdate), it can happend that no one worked on the contract
I want to show a table with those informations, for contract_id=3(ex) (this field is in tslines table) :
sum_week is a field, I don't want to recalculate with a SQL query
I don’t want to run a query for each weeks to check for each user if he worked on a contract because that would become a problem if I have ex : 30 weeks with 30 users that worked on the project..
I started by building an array of all possible « startdate »
//Selects min and max startdate of the tslines, use $dates->maxdate and ->mindate
$dates = $contract->tslines()->whereIsOfficial(true)->select(DB::raw('MAX(startdate) as maxdate, MIN(startdate) as mindate'))->first();
//Define first date declared in tslines
$loopdate = Carbon::parse($dates->mindate);
$maxdt = Carbon::parse($dates->maxdate);
//While loop to create array of date ranges from min to max
$date_count = 0;
$daterange = array();
while($loopdate->gt($maxdt) == false)
{
$daterange[] = $loopdate->format('Y-m-d');
$loopdate->addDays(7);
$date_count++;
}
I know I have to do some array manipulations but I really don’t know from where to start, even witht the queries..
I can get all the related tslines of contract by doing:
$contract->tslines()->get()
But I dont't know how to build an array that contains user information and all the startdate (even if he didn't work that week)
Can anybody give me some hints.. It would be greatly appreciated!!
Thanks in advance!
Raphaël
Let's start from what we know.
We know which users have worked on which contracts and on what date.
With your function above, we have the max date and the min date a user has started working on a contract.
Solution:
$tslines = $contract->tslines()->orderBy('user_id','ASC')->orderBy('startdate','ASC')->get();
//I didn't see any relationship calls to the user's object, so you'll have to add one of your own. I am assuming, your `tslines` has a relationship `user` here.
$userListResult = $contract->tslines()->with('user')->orderBy('user_id','ASC')->select(\Db::raw('distinct("user_id")')->get();
$dates = $contract->tslines()->whereIsOfficial(true)->select(DB::raw('MAX(startdate) as maxdate, MIN(startdate) as mindate'))->first();
$minDate = Carbon::parse($dates->mindate);
$maxDate = Carbon::parse($dates->maxdate);
//we flatten the array for future use.
$userList = array();
foreach($userListResult as $l)
{
$userList[$l->user_id] = $l->user->first_name.' '.$l->user->last_name;
}
//Assuming you are printing a table in blade
<table>
<?php
//Print the table headers
echo"<tr>
<td>User</td>";
$currDate = clone($minDate);
do
{
echo "<td>".$currDate->format('Y-m-d')."</td>";
$currDate->addDay();
}
while($currDate->diffInDays($maxDate) !== 0);
echo "</tr>";
//Print each user's row
foreach($userlist as $userid => $username)
{
echo "<tr>
<td>
$username
</td>";
$currDate = clone($minDate);
//loop through all the dates in range (min to max date)
do
{
$foundDate = false;
//We check if user has worked on that day
foreach($tslines as $row)
{
if($row->user_id === $userid && $row->startdate->format('Y-m-d') === $currDate->format('Y-m-d'))
{
//Print result if startdate & userid matches
echo "<td>{$row->sum_week}</td>";
$foundDate = true;
//Get out of the loops
break;
}
}
if(!$foundDate)
{
echo "<td>X (didn't work)</td>";
}
$currDate->addDay();
}
while($currDate->diffInDays($maxDate) !== 0);
echo "</tr>";
}
?>
</table>

Codeigniter - How to get values as array to use in next select with where_not_in

I have three tables; user, car and user_x_car. user_x_car holds users who own car; user_id and car_id are stored. I want to get users who don't own a car as follows:
$car_owner = $this->db->select()->from('user_x_car')->get()->result();
for ($i = 0; $i < count($car_owners); $i++)
$car_owner_id[$i] = $car_owner[$i]->user_id;
$non_car_owner = $this->db->select()->from('user')->where_not_in('id', $car_owner_id)->get()->result();
I get what I want, however, is there any way to bypass the for loop in the middle which creates and array of id's selected in the first select. Is there any way to get array of selected user_ids directly?
you can do it by two queries like
first one get all ids from user_x_car table
$temp1=array();
$temp=$this->db->distinct()->select('user_id')->get('user_x_car')->result_array();
then from user table fetch those users who have no cars
foreach($temp as $each)
{
array_push($temp1,$each['user_id']);
}
$rs=$this->db->where_not_in('id',$temp1)->get('user');
if($rs->num_rows()>0)
{
$data=$rs->result_array();
print_r($data);die;
}
$data will print all users who have no car. Please let me know if you face any problem.
function get_unread_notifications_ids()
{
//get unread notifications ids
$this->db->select('GROUP_CONCAT(fknotification_id) as alll');
$this->db->from("te_notification_status_tbl");
$this->db->where('read_status',0);
$ids=$this->db->get()->row();
return $idss=str_replace(",","','",$ids->alll);
}
and second function like this:
function get_unviewed_photos_events(){
$idss = $this->get_unread_notifications_ids();
$this->db->select('img.*',False);
$this->db->from("te_notifications_tbl notif");
$this->db->join('te_images_tbl img','img.id=notif.reference_id','LEFT OUTER');
$this->db->where("notif.id IN('".$idss."')");
$rslt = $this->db->get()->result_array();
return $rslt;
}
Query
$non_car_owner = $this->db->query('SELECT user.*
FROM user LEFT JOIN user_x_car ON user_x_car.id=user.id
WHERE table2.id IS NULL')->result();
Here users who are not on the table user_x_car
foreach($non_car_owner as $user){
echo $user->user_id;
}

group by and joining tables in linq to sql

I have the following 3 classes(mapped to sql tables).
Places table:
Name(key)
Address
Capacity
Events table:
Name(key)
Date
Place
Orders table:
Id(key)
EventName
Qty
The Places and Events tables are connected through Places.Name = Events.Place, while the Events and Orders tables: Events.Name = Orders.EventName .
The task is that given an event, return the tickets left for that event. Capacity is the number a place can hold and Qty is the number of tickets ordered by someone. So some sort of grouping in the Orders table is needed and then subtract the sum from capacity.
Something like this (C# code sample below)?
Sorry for the weird variable names, but event is a keyword :)
I didn't use visual studio, so I hope that the syntax is correct.
string eventName = "Event";
var theEvent = Events.FirstOrDefault(ev => ev.Name == eventName);
int eventOrderNo = Orders.Count(or => or.EventName == eventName);
var thePlace = Places.FirstOrDefault(pl => pl.Name == theEvent.Place);
int ticketsLeft = thePlace.Capacity - eventOrderNo;
If the Event has multiple places, the last two lines would look like this:
int placesCapacity = Places.Where(pl => pl.Name == theEvent.Place)
.Sum(pl => pl.Capacity);
int ticketsLeft = placesCapacity - eventOrderNo;
On a sidenote
LINQ 101 is a great way to get familiar with LINQ: http://msdn.microsoft.com/en-us/vcsharp/aa336746

Resources