Put value in datatable group by month - c#

I have this datatable in c#
Date Employee Job1 Job2 Job3
1/1/2012 a 1 1 1
1/1/2012 b 2 2 2
1/1/2012 c 2 1 4
1/1/2012 d 4 2 1
1/2/2012 a 3 2 5
1/2/2012 b 2 2 2
1/2/2012 c 3 3 3
1/2/2012 d 1 1 1
1/3/2012 a 5 5 5
1/3/2012 b 2 2 6
1/3/2012 c 1 1 1
1/3/2012 d 2 3 4
2/1/2012 a 2 2.5 2
2/1/2012 b 5 5 2
2/1/2012 c 2 2 2
2/2/2012 a 3 3 3
2/2/2012 b 2 3 3
3/1/2012 a 4 4 11
3/5/2012 a 14 42.5 15
3/6/2012 a 21 12.143 22
3/8/2012 a 8.9 45 27
3/8/2012 b 4.4 25 31
I want to loop through the values monthwise such that i can store the value in a datatable and will do the other calculation with that. Here with this example it will have three datatable, first with january values, another one with feb and last one with march rows. How can this be done by Linq. Please suggest the Linq syntax which will group the results month wise.
var monthEmpGroups = dt.AsEnumerable()
.Select(r => new
{
Year = DateTime.Parse(r.Field<string>("DATE")).Year,
Month = DateTime.Parse(r.Field<string>("DATE")).Month.ToString()
})
.GroupBy(x => x.Month);
var dtf = CultureInfo.CurrentCulture.DateTimeFormat;
foreach (var empGroup in monthEmpGroups)
{
int month = int.Parse(empGroup.Key);
string colName = dtf.GetMonthName(month);
// Here i want to get all the rows where month is colName (i.e.january, feb, march)
}
Please suggest if there is other way around to get the values month wise using LINQ.

You should move getting items for every group into monthEmpGroups query:
var monthEmpGroups = (from r in dt.AsEnumerable()
let month = DateTime.Parse(r.Field<string>("DATE")).Month
group r by month into g
select new { Month = g.Key, Items = g.ToList() });
With that you can easily get desired results:
var dtf = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat;
foreach (var empGroup in monthEmpGroups)
{
int month = empGroup.Month;
string colName = dtf.GetMonthName(month);
List<DataRow> items = empGroup.Items;
}

Related

SQL to LINQ - Getting Wrong Results

If a user selects 07-07-2016, I want to count how many times billdays > 30 for that billdate month, for the past 12 months.
Query is this:
select COUNT(*) as 'BillsOver30' from pssuite_web.pujhaccd
where billdays>30 and DATEDIFF(month,'07-07-2016', GETDATE()) <= 13
Group By Month(billdate)
Result is this:
1784 (July)
1509 (June)
2986 (May)
2196 (etc)
5853
3994
1753
1954
869
1932
629
1673
LINQ query is:
DateStart = '07-07-2016' (from a textbox on view)
DateTime earliestDate = objdate1.DateStart.Value.AddMonths(-13);
var custQuery9 = (from m in DataContext.pujhaccds
where m.billdays > 30 &&
m.billdate >= earliestDate &&
m.billdate <= objdate1.DateStart
group m by m.billdate.Value.Month into p
select new Date1()
{
theMonth = p.Key,
theCount = p.Count()
});
Results are:
Month Count
1 1029
2 1018
3 1972
4 1519
5 2657
6 2019
7 1206
8 1023
9 761
10 1620
11 354
12 931
You can see that the LINQ query is way off.
Doesn't matter what date I put in, the result always stays the same. Rather than 12 months from starting date.
I must be writing it wrong, thanks.

Query to select all rows with a condition

I need to make a query that select all rows belong to a ID from the datatable where Lesson from that ID has two specific values. For example ID 2 and 3 have lessons D and E that I want to take all the rows of ID 2 and ID 3.
My data is in MS Access.
MY Programming language is C#.
I already try to write some a query
"SELECT * FROM MainData WHERE ID IN ( SELECT ID FROM MainData GROUP BY ID HAVING (Lesson ='" + txtbox_startsubject.Text + "' and '" + TargetPoint + "'))";
The format of data:
ID Lesson Time Score
1 C 165 4
1 E 190 3
1 H 195 3
1 I 200 4
2 A 100 2
2 B 150 5
2 D 210 2
2 R 10 3
2 E 110 4
3 D 130 5
3 E 190 5
3 H 210 4
3 I 160 4
3 J 110 4
4 E 120 3
4 H 150 4
4 J 170 4

How to calculate count?

I want to calculate the count data from data table dt based on time and I have to store the counts on different variables.
Sample DB :
ID File_Name Uploaded_Time
----- --------- -------------
1 abc 3/18/2015 12:03:26 AM
1 abc 3/18/2015 12:10:26 AM
1 abc 3/18/2015 1:47:26 AM
1 abc 3/18/2015 2:17:52 AM
2 abc 3/18/2015 3:55:26 AM
1 abc 3/18/2015 6:12:44 AM
2 abc 3/18/2015 8:55:26 AM
2 abc 3/18/2015 10:55:26 AM
2 abc 3/18/2015 11:49:26 AM
1 abc 3/18/2015 12:55:26 PM
1 abc 3/18/2015 1:47:26 PM
1 abc 3/18/2015 2:47:26 PM
1 abc 3/18/2015 4:23:15 PM
1 abc 3/18/2015 6:47:26 PM
2 abc 3/18/2015 8:33:45 PM
Code :
protected void btnSubmit_Click(object sender, EventArgs e)
{
CommunicationTableAdapters.tbl_splited_detailsTableAdapter sd;
sd = new CommunicationTableAdapters.tbl_splited_detailsTableAdapter();
DataTable dt = new DataTable();
dt = sd.GetSiteUploadDetails(ddlSiteID.SelectedValue, txtDate.Text);
foreach (DataRow row in dt.Rows)
{
if (dt.Rows.IndexOf(row) != 0)
{
string uplodedtime = (row["Uploaded_Time"].ToString());
}
}
}
Example :
Calculate the count in between 12:00:00 AM to 1:00:00 AM and store in a variable. Like this I want to calculate 24 hrs count and store in 24 variable.
From the above sample DB, the required output is
variable count
-------- -----
hour1 2
hour2 1
hour3 1
hour4 1
hour5 0
hour6 0
hour7 1
hour8 0
hour9 1
hour10 0
hour11 1
hour12 1
hour13 1
hour14 1
hour15 1
hour16 0
hour17 1
hour18 0
hour19 1
hour20 0
hour21 1
hour22 0
hour23 0
hour24 0
This should do it:
var result =
dt.AsEnumerable()
.GroupBy (x => x.Field<DateTime>("Uploaded_Time").Hour)
.Select (x => new { Hour = x.Key, Count = x.Count() });
And if you want to to get a 0 for non existing values use the above expression with:
result = from hour in Enumerable.Range(0, 24)
join item in result on hour equals item.Hour into g
from item in g.DefaultIfEmpty()
select new
{
Hour = hour == 0 ? 24 : hour,
Count = item == null ? 0 : item.Count
};
Since the data is already sorted on the basis of upload time so what you could do is take 5 variables and read each query from the upload time colm.
1st var mon = string till first '/'
2nd var day = string between first '/' and second '/'
3 rd var for year
4th variable for the hour time
and 5 th variable for a look ahead hour time
So in your ques it would be for first query
day = 18
mon = 3
year = 2015
hour_initial = 12
hour_ahead = 12
and increment count till the hour_ahead changes or the day changes.(which ever comes first) and upload count for that specific hour
Then change the hour_intial to next hour and continue the process.....
(this is the basic technique)

Lambda Linq Iqueryable group - add another grouping

I have a method that I use for generating a summary report, based on the options a user selects in pick lists, to count the number of a type of test that is completed in a region, with subset locations, within a date range.
Here's what the data looks like:
Completed Test Counts by Location
From 1 FEB 2015 to 1 MAR 2015
Total TestType Location Region Division
455 24 Hour Lab 1 City 1 Division A
28 24 Hour Lab 2 City 1 Division A
95 24 Hour Clinic Z City 2 Division A
189 24 Hour Clinic Y City 2 Division A
Here's what it might look like for a different test type, at the same time period:
Total TestType Location Region Division
285 48 Hour Lab 1 City 1 Division A
12 48 Hour Lab 2 City 1 Division A
75 48 Hour Clinic Z City 2 Division A
106 48 Hour Clinic Y City 2 Division A
Now, the users would like to see the summary breakdown by testType in one report (in SQL, adding another attribute to a group by). In my pick list of testTypeId, I am using 0 as my "All" item. In a perfect world, I'd have another addition to the IQueryable if testTypeId == 0, so that I can keep the same private method, rather than writing a new query.
Here's what we'd like the data to look like in the "ALL" situation:
Total TestType Location Region Division
455 24 Hour Lab 1 City 1 Division A
285 48 Hour Lab 1 City 1 Division A
59 12 Lead Lab 1 City 1 Division A
28 24 Hour Lab 2 City 1 Division A
12 48 Hour Lab 2 City 1 Division A
95 24 Hour Clinic Z City 2 Division A
75 48 Hour Clinic Z City 2 Division A
5 12 Lead Clinic Z City 2 Division A
189 24 Hour Clinic Y City 2 Division A
106 48 Hour Clinic Y City 2 Division A
8 12 Lead Clinic Y City 2 Division A
The example below shows what I have with what I'd like to add in it, but the syntax tells me I can't take an IQueryable containing an IGrouping and convert it to the target type of IQueryable.
Can anyone point me in a good direction here?
private CompletedCountReport GetCompletedCountsByRegion(int regionId, DateTime? startDate, DateTime? endDate, int testTypeId)
{
var ccRpt = new CompletedCountReport { CompletedCounts = new List<CompletedCount>(), StartDate = startDate, EndDate = endDate, SelectedRegionID = regionId};
var query = HolterTestDao.FindAll(new GetCompletedByRegionIdAndDates(regionId, startDate.Value, endDate.Value));
// a specific test type was selected
if (testTypeId > 0)
{
query = query.Where(x => x.HolterTestType == testTypeId);
}
// THIS IS WHAT I WANT TO ADD -> otherwise group by test type <- THIS IS WHAT I WANT TO ADD.
if (testTypeId == 0)
{
query = query.GroupBy(x => x.HolterTestType);
}
// order by locationID within the region.
query = query.OrderBy(x => x.Location.ID);
var htList = query.ToList();
// now Group by Location, to get counts.
var reportContents = htList.GroupBy(x => x.Location.ID);
foreach (var r in reportContents)
{
var rList = r.ToList();
var cc = new CompletedCount();
var loc = LocationDao.FindById(r.Key);
cc.Description = loc.Description;
cc.RegionId = loc.Region.ID;
cc.DivisionId = loc.Region.Division.ID;
cc.TestTypeId = testTypeId;
cc.Count = rList.Count;
ccRpt.CompletedCounts.Add(cc);
}
return ccRpt;
}
My solution was to OrderBy Location and HolterTestType, then GroupBy location for the basic contents, and then add another grouping in my loop through the results to get the counts by test type:
query = query.OrderBy(x => x.Location.ID).ThenBy(x => x.HolterTestType);
var htList = query.ToList();
// now Group by Location.
var reportContents = htList.GroupBy(x => x.Location.ID);
foreach (var r in reportContents)
{
//Group by TestType, to get counts.
var t = r.GroupBy(x => x.HolterTestType);
var tList = t.ToList();
foreach(var u in tList)
{
var cc = new CompletedCount();
var loc = LocationDao.FindById(r.Key);
cc.Description = loc.Description;
cc.RegionId = loc.Region.ID;
cc.DivisionId = loc.Region.Division.ID;
cc.TestTypeId = u.Key;
cc.Count = u.Count();
ccRpt.CompletedCounts.Add(cc);
}
}

C# LINQ query to use previous result if empty

I am having a datatable that is populated from an Access DB. The result looks like
Month | Sum
--------------
1 | 1464
2 | 1716
3 | 2125
4 | 2271
5 | 2451
6 | 2583
7 | 2671
9 | 2823
10 | 2975
You are right - nothing for august!
What I want is, that for august the same value as for july is used.
Currently I am using this LINQ query to add the data to a linechart:
for (int i = 1; i <= System.DateTime.Now.Month; i++)
{
var numbers = (from p in dTable.AsEnumerable()
where p.Field<int>("M") >= i
select p).First();
series2.Points.Add(new DataPoint { AxisLabel = i.ToString(), YValues = new double[] { Convert.ToDouble(numbers["Sum"]) } });
}
The chart is shown, but for august the september value is used. I assume it is something very basic that I am doing wrong but I simply canĀ“t figure it out.
Thanks in advance!
You are requesting all the months greater than the current month.
where p.Field<int>("M") >= i
So for August (8), your are retrieving September and greater (9, 10, 11, 12), not July (7).
You have to invert your constraint, and order by descending month:
var numbers = (from p in dTable.AsEnumerable()
where p.Field<int>("M") <= i
select p)
.OrderByDesc(p => p.Month)
.First();
You have to invert your logic:
var numbers = (from p in dTable.AsEnumerable()
where p.Field<int>("M") <= i
select p).Last();
It goes without saying that this doesn't work when there is no previous month.
UPDATE:
the above asumes that the table you are reading from is ordered. If that is not the case, you have to order yourself (as mentioned by Cyril Gandon):
var numbers = (from p in dTable.AsEnumerable()
where p.Field<int>("M") <= i
orderby p.Field<int>("M") descending
select p).First();

Categories

Resources