I have a sql table called predictions with data as below
Week Player Points
201101 Mark 7
201101 Mark 7
201101 Pete 7
201101 Pete 3
201101 Mark 5
201102 Mark 2
201102 Mark 3
201102 Pete 7
201102 Pete 5
201102 Mark 5
201103 Mark 7
201103 Mark 7
201103 Pete 7
201103 Pete 3
201103 Mark 5
Each row in the table represents a football match, hence several per week
The result I need is
Player Count of Weekly wins
Mark 2
Pete 1
So Mark had the most points in week 2011011 and 201103, Pete had the most points in week 201102
Getting the total number of points per player per week is easy. But I cannot work out how to take the highest from that weekly group and get to the result I need.
I have this all in sql query using the RANK function and then selecting all the players who have a rank of 1. This is good because if two players have the same score for a week they both get counted correctly. But I want a LINQ version because it is cool and fits my reworking of a web site!
Any help would be appreciated.
OK I have got this far which is summing the data for each player for each week. What i now need to do is pick the top entry for each week and count it against the player
(from p in FootballPredictions
where p.FootballMatches.WeekNum <= 201101 && p.Points != null
group p by new { p.FootballMatches.WeekNum, p.Player } into g
orderby g.Key.WeekNum, g.Sum(p => p.Points) descending
select new
{
WeekNum = g.Key.WeekNum,
Player = g.Key.Player,
Points = g.Sum(p => p.Points),
})
Giving
WeekNum Player Points
201033 ranteld 26 <--- 1 point
201033 nicolap 25
201033 Mark 25
201033 1969 cup winners 25
201033 footysi 24
201033 Brendan 22
201033 monty 22
201033 Sandra Phillips 21
201033 SPB 20
201033 John Poulton 20
201033 RobBrown 19
201033 Steve Gardner 17
201033 Nick 16
201033 MikeSpeke 15
201034 Sandra Phillips 32 <--- 1 point
201034 Steve Gardner 27
201034 ranteld 25
201034 John Poulton 23
201034 footysi 23
201034 Mark 17
201034 nicolap 13
201034 Brendan 13
201035 Brendan 34 <--- 1 point
201035 Sandra Phillips 34 <--- 1 point
201035 nicolap 31
201035 1969 cup winners 25
201035 MikeSpeke 24
201035 Steve Gardner 22
201035 Mark 20
201035 ranteld 20
201035 Football Freddie 16
So the real answer from this table is
Player Wins
Sandra Philips 2
Brendan 1
ranteld 1
Hope that clarifies
It was somewhat confusing to see that your query didn't seem to correspond to the data. So instead, this will be based on the data alone. The query should produce valid SQL so you won't have to use LINQ to Objects. You can adapt it to your tables with little modification.
var query = from pred in Predictions
group pred.Points by pred.WeekNum into week
join pred in Predictions
on new { WeekNum = week.Key, Points = week.Max() }
equals new { pred.WeekNum, pred.Points }
group 1 by pred.Player into player
let Wins = player.Count()
orderby Wins descending, player.Key
select new
{
Player = player.Key,
Wins,
};
Try:
p.Points.Any()
Instead of:
p.Points != null
This code seems to be what you need:
var result = this.DataList
.GroupBy(data => data.Week)
.Select(data=>
{
return data.GroupBy(item => item.Name)
.Select(item => new { Name = item.Key, SumPoints = item.Sum(v => v.Points) })
.OrderBy(item => item.SumPoints)
.FirstOrDefault();
})
.GroupBy(_=>_.Name)
.ToDictionary(_=>_.Key, _=>_.Count());
mine is quite long
var weeklyTopScore = from eachMatch in FootballPredictions
group eachMatch by eachMatch.week
into weekly
select new {week = weekly.Key, topScore = weekly.Max(match => match.points)};
var playerWins = from eachResult in weeklyTopScore
join entry in FootballPredictions
on eachResult.week equals entry.week
where eachResult.topScore == entry.points
group entry by entry.player
into winner
select new { player = winner.Key, wins = winner.Count() };
var result = from entry in playerWins
group entry by entry.wins
into summary
select new { player = summary.Select(data => data.player).Aggregate((cur, nex) => cur + ", " + nex), wins = summary.Key};
Just pass a datatable to following function (Please note that the code is in c#)
//dt should contain column points but not rank column
public static DataTable GetRankedDatatable(DataTable dt)
{
var rankedDt = (from row in dt.AsEnumerable()
orderby row.Field<string>("points")
select row).CopyToDataTable();
rankedDt.Columns.Add("rank");
int rank = 0;
for (int i = 0; i < rankedDt.Rows.Count - 1; i++)
{
rankedDt.Rows[i]["rank"] = rank;
if (rankedDt.Rows[i]["points"].ToString() != rankedDt.Rows[i + 1]["points"].ToString())
{
rank++;
}
}
rankedDt.Rows[rankedDt.Rows.Count - 1]["rank"] = rank;
return rankedDt;
}
Related
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.
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);
}
}
I'm using C# and SQL Server 2008 R2.
I have hour data like this:
Client_ID TheHour HourMin HourMAx
53026 09:00 7 9
53026 12:00 10 12
53026 15:00 13 15
53026 18:00 16 19
I will put TheHour into my combobox, that depends on computer hour.
When the computer hour is 10:00 then the value of my combobox:
12:00
15:00
18:00
09:00
My linq is :
int The_Hour = DateTime.Now.Hour;
var query = from o in oEntite_T.LS_CLIENTHORRAIRE
where o.CLIENT_ID == CLIENT_ID &&
The_Hour >= o.HEURE_MIN && The_Hour <= o.HEURE_MAX
select o;
LesListe = query.ToList();
It return only 1 value, which is 12:00.
That meant my combobox will select hour that depend on computer hour, but it leave the possibility for the user to select another hour.
Here is a working example in LINQPad, I also added a flag to indicate selected value.:
void Main()
{
var LS_CLIENTHORRAIREs = new List<LS_CLIENTHORRAIRE>
{
new LS_CLIENTHORRAIRE{TheHour="09:00",HourMin=7,HourMAx=9},
new LS_CLIENTHORRAIRE{TheHour="12:00",HourMin=10,HourMAx=12},
new LS_CLIENTHORRAIRE{TheHour="15:00",HourMin=13,HourMAx=15},
new LS_CLIENTHORRAIRE{TheHour="18:00",HourMin=16,HourMAx=19}
};
LS_CLIENTHORRAIREs.Dump();
int The_Hour = 10;
var query = from o in LS_CLIENTHORRAIREs
select new {o.TheHour,o.HourMin,o.HourMAx,selected = The_Hour >= o.HourMin && The_Hour <= o.HourMAx}
;
query.OrderBy (q => q.HourMAx>The_Hour ? 0 : 1).ThenBy (q => q.HourMAx).Dump();
}
public class LS_CLIENTHORRAIRE
{
public string TheHour{get;set;}
public int HourMin{get;set;}
public int HourMAx{get;set;}
}
Results
So, basically, you don't want to filter the list, you want to sort it, right?
First, you want to sort it by
whether the MaxHour is in the past
and then by
TheHour itself.
Example: Let's assume it is 10:00:
Client_ID TheHour HourMin HourMax MaxHourIsInThePast
53026 09:00 7 9 x
53026 12:00 10 12
53026 15:00 13 15
53026 18:00 16 19
Now you return a list that orders first by MaxHourIsInThePast (first those without x and then those with x) and then by TheHour.
Implementation is left as an exercise. Hint: You will need the LINQ order by keyword, and an expression similar to (o.HourMax < currentHour ? 2 : 1) will come in handy.
Let assume the computer hour is 10.
Then: your condition would be: HourMin <= 10 && HoureMax >= 10.
The first condition would return row 1 and 2. The second one would return row 2. The intersect will return only the second row, which is 12:00.
If you want to get all rows, just remove these conditions.
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();
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;
}