简体   繁体   中英

How to write this LINQ Query

Hi i have a datatable with following fields

DAT_START
GROUPBY
TXT_LATITTUDE
TXT_LONGITUDE
INT_DIRECTION
INT_CALL_DATA_TYPE
LNG_DURATION

And following is the LINQ query i am using

var data = (from r in dt.AsEnumerable()
where ((r.Field<DateTime>("DAT_START").TimeOfDay.Hours < 20) && (r.Field<DateTime>("DAT_START").TimeOfDay.Hours >= 4))
group r by new { CID = r["GroupBy"], CLatitude = r["TXT_LATITUDE"], CLongitude = r["TXT_LONGITUDE"],CDirection = r["INT_DIRECTION"], 
CCallType = r["INT_CALL_DATA_TYPE"],CDuration = r["LNG_DURATION"] }
into groupedTable
select new
{
   CellID = groupedTable.Key.CID,
   CallCount = groupedTable.Count(),
   Longitude = groupedTable.Key.CLongitude,
   Latitude = groupedTable.Key.CLatitude,
   Direction = groupedTable.Key.CDirection,
   CallType = groupedTable.Key.CCallType,
   Duration = groupedTable.Key.CDuration
}).OrderByDescending(s => s.CallCount);

It gives me result like this

CellID = 4057,CallCount = 84,Longitude = "",Latitude = "",Direction = "Incoming",CallType = "Voice",Duration = 50
CellID = 4057,CallCount = 8,Longitude = "",Latitude = "",Direction = "Outgoing",CallType = "Voice",Duration =97
CellID = 4057,CallCount = 56,Longitude = "",Latitude = "",Direction = "Incoming",CallType ="SMS" ,Duration = 0
CellID = 4057,CallCount = 41,Longitude = "",Latitude = "",Direction = "Outgoing",CallType = "SMS",Duration = 0

Now i want result like this

CellID = 4057, TotalCommCount = 204, TotalDuration = 147, INSMSCount = 56,OutSMSCount = 41, INVoiceCount = 84,OutVoiceCount = 8,InVoiceDuration =50,OutVoiceDuration = 47

How can i do this. I am struck over here..

It looks like you're grouping by far too much at the moment, which is why you're getting multiple rows. I suspect you want something like this:

from r in dt.AsEnumerable()
where r.Field<DateTime>("DAT_START").TimeOfDay.Hours < 20 && 
      r.Field<DateTime>("DAT_START").TimeOfDay.Hours >= 4
group r r["GroupBy"] into g         
select new
{
    CellID = g.Key,
    TotalCommCount = g.Count(),
    TotalDuration = g.Sum(r => r.Field<long>("LNG_DURATION")),
    InSMSCount = g.Count(r => r.Field<string>("DIRECTION") == "Incoming" &&
                              r.Field<string>("CALL_TYPE") == "SMS"),
    OutSMSCount = g.Count(r => r.Field<string>("DIRECTION") == "Outgoing" &&
                               r.Field<string>("CALL_TYPE") == "SMS"), 
    InVoiceCount = g.Count(r => r.Field<string>("DIRECTION") == "Incoming" &&
                                r.Field<string>("CALL_TYPE") == "Voice"),
    OutVoiceCount = g.Count(r => r.Field<string>("DIRECTION") == "Outgoing" &&
                                 r.Field<string>("CALL_TYPE") == "Voice"),
    InVoiceDuration = g.Where(r => r.Field<string>("DIRECTION") == "Incoming" &&
                                r.Field<string>("CALL_TYPE") == "Voice")
                       .Sum(r => r.Field<long>("DURATION"))
    OutVoiceDuration = g.Where(r => r.Field<string>("DIRECTION") == "Outgoing" &&
                                    r.Field<string>("CALL_TYPE") == "Voice"),
                       .Sum(r => r.Field<long>("DURATION"))
 } into summary
 order by summary.TotalCommCount descending
 select summary;

I suggest you create a view in your SQL database where you can simply aggregate what you need and then you use that view in your Linq query - this will perform fast and it is easy to write.

Sketch of design:

Since the description of your requirements is not totally clear, I have made assumptions. Create a SQL view such as (it's just to show the idea, change it according to your needs):

CREATE VIEW [dbo].[vSumDurations]
AS 
select  c.CellId, j1.SumDuration1 as TotalDuration, 
        j2.SumDuration2 as GroupedDuration, j1.CallCount  
from (select distinct t.CID as CellId from [dbo].[YourTable] t) c
left join (select t1.CID as CellId, sum(LNG_Duration) as SumDuration1, 
            count(*) as CallCount from [dbo].[YourTable] t1 
            Group By t1.CID) j1 
on c.CellId=j1.CellId           
left join (select t2.CID as CellId, sum(LNG_Duration) as SumDuration2 
            from [dbo].[YourTable] t2 
            Group by t2.CID, t2.Direction, t2.CallType) j2 
on c.CellId=j2.CellId

(You know you can easily add this view to your *.EDMX by using "update model from database" in the context menu of the entity diagram page and then tick-mark the view vSumDurations in the "tables/views" section of the dialog which pops up.)

After this preparation your Linq query is very simple because everything is already done in the view. Hence, the code looks like:

var dc = this; // in LinqPad you can set your data context
var data = (from d in dc.vSumDurations select d).OrderByDescending(s => s.CallCount);
data.Dump();

Note: The example is made for LinqPad - you will need a different data context in your real code. Linqpad does not need dc , but it is easier if you declare it for convenience reasons because in your real code you have to provide it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM