How do I achieve this in C# - linq-to-sql

How do I aggregate conditionally in C#
Like in the following vb code:
Dim movement = From item In dbo.VIEWITEMMOVEMENTs
Where item.DATETRANSFERRED.Value.Date = Me.DateTimePicker1.Value.Date
Group By item.DATETRANSFERRED.Value.Date, item.ITEMDESCRIPTION
Into moved = Group, sold = Sum(item.QUANTITYSOLD), [IN] = Sum(If(item.QUANTITY < 0.0, 0.0, item.QUANTITY)), Out = Sum(If(item.QUANTITY > 0, 0, item.QUANTITY))
Select ITEMDESCRIPTION, sold, [IN], Out Order By ITEMDESCRIPTION Ascending
Me.DataGridView1.DataSource = movement

var result = (
from item in dbo.VIEWITEMMOVEMENTs
where item.DATETRANSFERRED.Value.Date == this.DateTimePicker1.Value.Date
group item by new { item.DATETRANSFERRED.Value.Date, item.ITEMDESCRIPTION }
into g
select new
{
g.Key.ITEMDESCRIPTION,
sold = g.Sum(x => x.QUANTITYSOLD),
IN = g.Sum(x => (x.QUANTITY <0 ? 0 : x.QUANTITY)),
Out = g.Sum(x => (x.QUANTITY > 0 ? 0 : x.QUANTITY))
}
).OrderBy(d => d.ITEMDESCRIPTION);

if you are trying to convert that snippet of code. you could use the converters like
VB to C#
Hope this helps.

Related

What's the best process for upgrading my appointment scheduler in Laravel?

I got an idea to change the way I currently schedule appointments. Currently, I have an officehours table with 1 record per appointment time per day, as such weekday, appt_time, type_id, provider_id
I was thinking it might be better to have the officehours table instead have 1 record per day instead, with opening_time, closing_time, weekday, provider_id
I also have a closed table, which has open(time), close(time), closed (boolean), provider_id.
Then I have the appts table which saves appt_date, appt_time, client_id, appt_type_id, provider_id, etc
What I did in the past was create arrays of upcoming dates, booked appointments, officehours, and closures. I'd loop through the dates, and filter the arrays to match and run my logic. Anything that wasn't booked or closed would be pushed into an available array and I'd display that. Seems complicated, and it was.
I was wondering if it would be better to use Carbon dates, starting with the first day of the current week, and adding a day until 2 weeks of appointments is done. It's a lot of nested loops, though.
for each day, I have each provider (loop) and for each provider I'd use Carbon to start with the opening time and add the appointment if available and skip 10 minutes or the length of the appointment that is already booked before moving on to the next time.
This way I was using Eqoquent Collections instead of standard arrays, and I'm feeling as though they are slower and more difficult to work with but I'll stick it out if someone who knows better can help me understand.
Anyone have a great idea of how to make this happen in a great way (dare I say best)? I have a hard time simplifying things.
My old code:
public function index(Request $request)
{
$type = str_contains($request->path(), 'calendar') ? 1 : 2;
$doc = str_contains($request->path(), 'drdave') ? 2 : 1;
// getDates($displayWeeks, $daysInWeek) default 2, 4
$settings = Setting::where('type','public')->first();
$days = CalendarController::getDates($settings->weeks_visible ?: 2, $settings->days_in_week ?: 6);
$display = CalendarController::getApptCalendarData($days, $type, $doc);
return view('calendar', ['display'=>$display, 'daysInWeek'=>$settings->days_in_week, 'type'=>$type]);
}
// returns a list of days to be displayed on the calendar
public function getDates($displayWeeks = null, $daysInWeek = null) {
$today = date('Y-m-d',strtotime("today")); // today’s date
$thisday = date('w',strtotime("today")); // today’s weekday
$lastmon = date('m/d/Y',strtotime("last monday")); // last monday
$nextmon = date('m/d/Y',strtotime("next monday")); // next monday
$now = date("h:i:s"); // current time
$days = [];
// DETERMINE STARTING MONDAY
if ($thisday < 1 || $thisday > 6) // today is Sun, Fri, Sat
{
$day0 = date('m/d/Y',strtotime('-1 day', strtotime($nextmon)));
} elseif ($thisday > 1) // today is Tue, Wed, Thu, Fri
{
$day0 = date('m/d/Y',strtotime('-1 day', strtotime($lastmon)));
} else {
$day0 = date('m/d/Y',strtotime('-1 day', strtotime($today)));
}
// GENERATE LIST OF DATES
$displayWeeks = $displayWeeks ? $displayWeeks : 2; // # of weeks shown
// 4 = M-TH, 5 = M-F, 6 = M-Sat, 7 = full week
$daysInWeek = $daysInWeek ? $daysInWeek : 4;
$showSunday = $daysInWeek === 7 ? true : false;
// create array of dates to display
for ($w = 1; $w <= $displayWeeks; $w++) {
for ( $i = 0; $i < $daysInWeek; $i++ ) {
$x = $showSunday === false ? $i + 1 : $i;
$day = strftime("%Y-%m-%d", strtotime( '+' . $x .' day', strtotime($day0)));
array_push($days, $day);
}
// change to the next week
$day0 = strftime("%Y-%m-%d", strtotime( '+7 days', strtotime($day0)));;
}
return $days;
}
// returns list of appointments for doc (1 for Mel, 2 for Dave)
public function getApptCalendarData($days, $type = 0, $doc = 1) {
$start = $days[0];
$end = $days[count($days)-1];
// $closed = Closed::select('*')->where(['closed_date' >='$start', 'closed_date' <= '$end'])->orderBy('closed_date','ASC');
$closed = DB::select("SELECT AM_PM_DAY, closed_date, reason, open, close, date_format(open,'%l:%i %p') as opentime, date_format(close,'%l:%i %p') as closetime from closed WHERE closed_date >='$start' AND closed_date <= '$end' ORDER BY closed_date ASC");
$appointments = DB::select("SELECT appt_date, appt_time, appt_note, appt_reminder, reminder_cell, date_format(appt_time,'%l:%i %p') as time, patient_id, patient.id, patient.nickname, month(appt_date), year(appt_date), appt_type_id, appt_type.id, appt_type.appt_abbr, appt_type.appt_type_name, appt.id as appt_id, appt_status_id FROM appt, patient, appt_type WHERE appt.patient_id = patient.id and appt_date >= '$start' AND appt_date <= '$end' AND appt.appt_type_id = appt_type.id AND appt_status_id NOT IN ( '" . implode( "', '" , $this->RECALL ) . "' ) ORDER BY appt_date, appt_time ASC");
$available = $type > 0 ? DB::select("SELECT appt_time, dayslot, doctor_id, type, date_format(appt_time,'%l:%i %p') as time from officehour WHERE type = '$type' ORDER BY dayslot asc, appt_time asc") : DB::select("SELECT appt_time, dayslot, doctor_id, type, date_format(appt_time,'%l:%i %p') as time from officehour ORDER BY dayslot asc, appt_time asc");
$display = [];
// create an array of objects to display of date, closedInfo, appointments, and availability for each day
foreach($days as $day) {
$item = new class{};
$item->day = $day;
$item->isAdmin = false;
$item->today = date('Y-m-d',strtotime("today")) === date('Y-m-d', strtotime($day)); // today’s date
$item->show = date('Y-m-d', strtotime($day)) >= date('Y-m-d', strtotime('today'));
$item->displayDay = date("l F jS", strtotime($day));
$dayofweek = date('N',strtotime($day)); // for dayslot of office hours
$c = $closed;
$closedToday = array_filter(
$c,
function ($e) use (&$day) {
return $e->closed_date == $day;
}
);
$item->isclosed = count($closedToday) === 0 ? false : true;
if($item->isclosed === true) {
$item->closedInfo = head($closedToday);
$item->closedInfo->message = $item->closedInfo->AM_PM_DAY === 'DAY' ? "Closed Today" : ($item->closedInfo->AM_PM_DAY === 'AM' ? 'Morning Closed' : 'Afternoon/Evening Closed');
}
// filter booked appointments for this day
$existing = array_filter(
$appointments,
function ($e) use (&$day) {
return $e->appt_date == $day;
}
);
// LIST TIMES BOOKED FOR COMPArISON
$existing_times = array_column($existing, 'appt_time');
// office hours for this day of the week
$item->hours = array_filter(
$available,
function ($e) use (&$dayofweek) {
return $e->dayslot == $dayofweek;
}
);
// DISPLAY ARRAYS
$item->availability = [];
$item->adminAppts = [];
$appts = [];
// CHECK FOR AVAILABLE OR BOOKED, AND FILL LISTS
foreach($item->hours as $hour) {
// IS THE TIME BOOKED?
$freetime = (in_Array($hour->appt_time, $existing_times) === true) ? false : true;
// ADD the existing appt to the list
if($freetime === false && count($existing) > 0) {
// add this item to the admin appts list
$pushed = array_shift($existing);
array_push($appts, $pushed);
}
// CHECK IF TIME IS OPEN
$opentime = $item->isclosed === false ? true : false;
if($item->isclosed === true) {
$openAMPMDAY = (($item->closedInfo->AM_PM_DAY !== substr($hour->time, -2)) && ($item->closedInfo->AM_PM_DAY !== 'DAY'));
$openHOURS = (($hour->appt_time >= $item->closedInfo->open && $hour->appt_time <= $item->closedInfo->close));
$opentime = ($openHOURS === true && $openAMPMDAY === true);
}
// ADD THE OPEN TIME TO THE LIST
if($freetime === true && $opentime === true ) {
array_push($appts, $hour);
}
}
// ADD ANY REMAINING APPOINTMENTS TO THE LIST
foreach($existing as $remaining) {
array_push($appts, $remaining);
}
// sort the appointments by time
usort($appts, fn($a, $b) => strcmp($a->appt_time, $b->appt_time));
// split the appointments into 2 lists for column display
$count = ceil(count($appts) /2);
array_push($item->adminAppts, array_splice($appts, 0, $count, true));
array_push($item->adminAppts, array_diff_key($appts, $item->adminAppts));
// array_push($item->adminAppts, $session);
array_push($display, $item);
}
return $display;
}
To give you an idea of how it looks, https://adjust-me.com/calendar for existing, or https://adjust-me.com/newbies for new people. What it's NOT doing is displaying the closure info for each doctor with their appointments, the labeling sucks, and I need separate schedules depending on the type of appointment.
I was hoping to make things simpler for clients and allow them to book any time in the range, but newbies are 60 minutes so I'd need to switch from 1 record per time slot to make that work. That said I don't want it to lag.

EntityFramework groupby not working as on mysql

I have the following sql query
SELECT statusId, statusName,sum(durationSeconds)/3600 as duration
FROM status
where date_local >=date
and durationSeconds > 0
group by statusId
order by duration desc;
I'm trying to do the same using EF core.
var result = await context.status
.Where(e => e.ShiftdateLocal >= date && e.Durationseconds > 0)
.Select(e => new LiveStatusProductionViewModel
{ StatusId = e.statusId, StatusName = e.statusName, Duration = e.Durationseconds / 3600 })
//.GroupBy(e => e.Duration)
.OrderByDescending(e => e.Duration)
.ToListAsync();
What am I doing wrong? How do I achieve the same result as on mysql?
You have did only half of work, added GroupBy but not added correct projection.
var result = await context.status
.Where(e => e.ShiftdateLocal >= date && e.Durationseconds > 0)
.GroupBy(e => new { e.statusId, e.statusName })
.Select(g => new LiveStatusProductionViewModel
{
StatusId = g.Key.statusId,
StatusName = g.Key.statusName,
Duration = g.Sum(x => x.Durationseconds / 3600)
})
.OrderByDescending(e => e.Duration)
.ToListAsync();

Evaluation of nested IF in MySQL

I found this code in a WordPress plugin, but I cannot understand what does it mean or how it can be read.
Can somebody to help me underdstaint this code :?
IF(agr_sam_ads.ad_users = 0, TRUE, IF(agr_sam_ads.ad_users_reg = 1, IF(agr_sam_ads.x_ad_users = 1, NOT FIND_IN_SET("admin", agr_sam_ads.x_view_users), TRUE ....
I have not paste the whole query because it is huge. In what I am interested to be helped is the part of the Query that looks like that:
IF(expression, value, IF(expression, IF(expression, SQL Logical Query, value ...
I have not see this syntax, and I don't know where to search for that. In MySQL documentation the IF statement syntax is like that : http://dev.mysql.com/doc/refman/5.0/en/if.html and it is not looks like the one I have paste above.
Just for the users are interested in the full code, the code is here:
SELECT
agr_sam_places.id,
agr_sam_places.name,
agr_sam_places.description,
agr_sam_places.code_before,
agr_sam_places.code_after,
agr_sam_places.place_size,
agr_sam_places.place_custom_width,
agr_sam_places.place_custom_height,
agr_sam_places.patch_img,
agr_sam_places.patch_link,
agr_sam_places.patch_code,
agr_sam_places.patch_adserver,
agr_sam_places.patch_dfp,
agr_sam_places.patch_source,
agr_sam_places.trash,
(
SELECT
COUNT(*)
FROM
agr_sam_ads
WHERE
agr_sam_ads.pid = agr_sam_places.id
AND
agr_sam_ads.trash IS FALSE
) AS ad_count,
(
SELECT
COUNT(*)
FROM
agr_sam_ads
WHERE
agr_sam_ads.pid = agr_sam_places.id
AND
agr_sam_ads.trash IS FALSE
AND
(
IF(agr_sam_ads.ad_users = 0, TRUE, IF(agr_sam_ads.ad_users_reg = 1, IF(agr_sam_ads.x_ad_users = 1, NOT FIND_IN_SET("admin", agr_sam_ads.x_view_users), TRUE
)
AND
IF(agr_sam_ads.ad_users_adv = 1, (agr_sam_ads.adv_nick <> "admin"), TRUE), FALSE)))
AND
(
(
agr_sam_ads.view_type = 1
)
OR
(
agr_sam_ads.view_type = 0
AND
(
agr_sam_ads.view_pages+0 & 256
)
)
)
AND
(
agr_sam_ads.ad_cats = 0
)
AND
(
agr_sam_ads.ad_authors = 0
)
AND
IF(agr_sam_ads.ad_schedule, CURDATE() BETWEEN agr_sam_ads.ad_start_date AND agr_sam_ads.ad_end_date, TRUE)
AND
IF(agr_sam_ads.limit_hits, agr_sam_ads.hits_limit > agr_sam_ads.ad_hits, TRUE)
AND
IF(agr_sam_ads.limit_clicks, agr_sam_ads.clicks_limit > agr_sam_ads.ad_clicks, TRUE)
AND
(
agr_sam_ads.ad_weight > 0
)
) AS ad_logic_count,
(
SELECT
COUNT(*)
FROM
agr_sam_ads
WHERE
agr_sam_ads.pid = agr_sam_places.id
AND
agr_sam_ads.trash IS FALSE
AND
(
IF(agr_sam_ads.ad_users = 0, TRUE, IF(agr_sam_ads.ad_users_reg = 1, IF(agr_sam_ads.x_ad_users = 1, NOT FIND_IN_SET("admin", agr_sam_ads.x_view_users), TRUE)
AND
IF(agr_sam_ads.ad_users_adv = 1, (agr_sam_ads.adv_nick <> "admin"), TRUE), FALSE)))
AND
(
(
agr_sam_ads.view_type = 1
)
OR
(
agr_sam_ads.view_type = 0
AND
(
agr_sam_ads.view_pages+0 & 256
)
)
)
AND
(
agr_sam_ads.ad_cats = 0
)
AND
(
agr_sam_ads.ad_authors = 0
)
AND
IF(agr_sam_ads.ad_schedule, CURDATE() BETWEEN agr_sam_ads.ad_start_date AND agr_sam_ads.ad_end_date, TRUE)
AND
IF(agr_sam_ads.limit_hits, agr_sam_ads.hits_limit > agr_sam_ads.ad_hits, TRUE)
AND
IF(agr_sam_ads.limit_clicks, agr_sam_ads.clicks_limit > agr_sam_ads.ad_clicks, TRUE)
AND
IF(agr_sam_ads.ad_weight > 0, (agr_sam_ads.ad_weight_hits*10/(agr_sam_ads.ad_weight*1000)) < 1, FALSE)
) AS ad_full_count
FROM
agr_sam_places
WHERE
agr_sam_places.id = 10
AND
agr_sam_places.trash IS FALSE;
It should be read as:
IF (
expression,
valueIfExpressionIsTrue,
valueIfExpressionIsValue
)
So to take part of your code:
IF(
agr_sam_ads.ad_users = 0,
TRUE,
IF(
agr_sam_ads.ad_users_reg = 1,
2,
3
)
)
I see that you're familiar with PHP, so essentially if this was PHP, the code would be
if ($arg_sam_ads_ad_users == 0) {
return true;
} else {
if ($arg_sam_ads_ad_users_reg == 1) {
return 2;
} else {
return 3;
}
}
This is basically creating an IF-ELSE tree without using the IF _ THEN _ ELSE _ ENDIF syntax.
Take the following example:
IF(1=0, 1, IF(1=1, 1, 0))
This is the equivalent of the following with C syntax:
IF (1=0) {
1
}
ELSE IF (1=1) {
1
}
ELSE {
0
}
The more common SQL syntax is the following:
IF 1=0 THEN
1;
ELSEIF 1=1 THEN
1;
ELSE
0;
ENDIF;

EF 4.1 - code first - query no longer works

I moved from using an edmx file to code first. The following query is no longer working (it's basically a group by with limit 1) :
(from sc in dbContext.student_courses
where
sc.student_id == student.id
&& sc.course_id == course.id
&& sc.complete_flag == 1
group sc by new
{
sc.complete_flag,
sc.direct_to_test_flag,
sc.dept_purchase_flag,
sc.issue_ce_flag,
sc.unlimited_purchase_flag,
sc.survey_taken
}
into scgroup
select new StudentCourseDetails
{
completeVideo = scgroup.Max(x => x.complete_flag),
directToTest = scgroup.Max(x => x.direct_to_test_flag),
isDepartmentPurchase = scgroup.Max(x => x.dept_purchase_flag),
issueCE = scgroup.Max(x => x.issue_ce_flag),
isUnlimitedPurchase = scgroup.Max(x => x.unlimited_purchase_flag),
surveyTaken = scgroup.Max(x => x.survey_taken)
}).FirstOrDefault();
The resulting sql :
SELECT `Limit1`.`complete_flag`,
`Limit1`.`C1`,
`Limit1`.`C2`,
`Limit1`.`C3`,
`Limit1`.`C4`,
`Limit1`.`C5`,
`Limit1`.`C6`
FROM (SELECT `GroupBy1`.`A1` AS `C1`,
`GroupBy1`.`A2` AS `C2`,
`GroupBy1`.`A3` AS `C3`,
`GroupBy1`.`A4` AS `C4`,
`GroupBy1`.`A5` AS `C5`,
`GroupBy1`.`A6` AS `C6`,
`GroupBy1`.`K1` AS `complete_flag`
FROM (SELECT Max(`complete_flag`) AS `A1`,
Max(`direct_to_test_flag`) AS `A2`,
Max(`dept_purchase_flag`) AS `A3`,
Max(`issue_ce_flag`) AS `A4`,
Max(`unlimited_purchase_flag`) AS `A5`,
Max(`survey_taken`) AS `A6`
FROM `student_courses` AS `Extent1`
WHERE ((`Extent1`.`student_id` = 3885 /* #p__linq__0 */)
AND (`Extent1`.`course_id` = 606 /* #p__linq__1 */))
AND (1 = `Extent1`.`complete_flag`)
GROUP BY `Extent1`.`complete_flag`,
`Extent1`.`dept_purchase_flag`,
`Extent1`.`direct_to_test_flag`,
`Extent1`.`issue_ce_flag`,
`Extent1`.`survey_taken`,
`Extent1`.`unlimited_purchase_flag`) AS `GroupBy1`
LIMIT 1) AS `Limit1`
The problem is that when it adds the limit 1, it also adds an extra column :
GroupBy1.K1 AS complete_flag - which doesn't exist.
Any thoughts ?

Linq to Sql - Converting a join and sum from sql to linq

I have crawled over several of the various questions on Linq-to-SQL dealing with joins, counts, sums and etc.. But I am just having a difficult time grasping how to do the following simple SQL Statement...
SELECT
tblTechItems.ItemName,
SUM(tblTechInventory.EntityTypeUID) AS TotalOfItemByType
FROM
tblTechInventory
INNER JOIN
tblTechItems ON tblTechInventory.ItemUID = tblTechItems.ItemUID
GROUP BY
tblTechInventory.StatusUID,
tblTechItems.ItemName,
tblTechInventory.InventoryUID
HAVING
tblTechInventory.StatusUID = 26
Try this:
var query = from e in db.tblTechInventory
join f in db.tblTechItems on e.ItemUID equals f.ItemUID into x
from y in x
group e by new { e.StatusUID, y.ItemName, e.InventoryUID } into g
where e.StatusUID == 26
select new {
g.Key.ItemName,
TotalOfItemByType = g.Sum(e => e.EntityTypeUID)
};
I'll give it a shot...
var results = tblTechInventory
.Join(tblTechItems, i=> i.ItemUID, o => o.ItemUID, (i,o) => new {i.ItemName, o.EntityTypeUID, o.StatusUID, i.ItemName, o.InventoryUID})
.Where(o => o.StatusUID == 26)
.GroupBy(g => new {g.StatusUID, g.ItemName, g.InventoryUID}, (gr, items) => new {gr.Key.ItemName, items.Sum(i => i.EntityTypeUID)});