2

I have data in a table as below

RowId | User | Date 
--------------------------
  1     A     2015-11-11 08:50:48.243
  2     A     2015-11-11 08:51:01.433
  3     B     2015-11-11 08:51:05.210

Trying to get the data as below:

User, Date,        Count
  A   2015-11-11     2
  B   2015-11-11     1

 Select User,Date,Count(User) from Table1 
 Group By User,Date

It is returning me 3 rows because of time involved in Date field. How to get this in SQL and Linq. Please suggest me.

EDITING:

I am able to get it in SQL

 Select User,Cast(Date as Date),Count(User) from Table1 
 Group By User,Cast(Date as Date)    

EDITING:

adding linq query

var details = db.table1.GroupBy( r => new { r.RowId,r.User,r.Date})
.Select(g => new {Name = g.Key, Count = g.Count()}).ToList();
user1893874
  • 823
  • 4
  • 15
  • 38

3 Answers3

0

If the time is the problem, you can first convert it:

select User, CAST(dateColumn AS DATE) as dateConverted
into #tempTable
from myTable

then using a window function or a group by:

select *,
    count(user) over (partition by date) as userCount
    from #tempTable

This should work in SQL server, don't know about Linq

edit: If the date part is the problem, just select into from your table to a table with the casted date. Then you won't have this problem in Linq.

CM2K
  • 833
  • 3
  • 18
  • 38
  • There i no need to create a temporary table for that. Check the question. The User already have a solution for TSQL – CodeNotFound Nov 11 '15 at 15:35
  • he added the solution after i wrote my response. – CM2K Nov 11 '15 at 15:37
  • Yes, I need help in Linq. – user1893874 Nov 11 '15 at 15:37
  • Why don't you try as I suggested? just take your table and select into another with the date casted. Then use that one in Linq? Will this work? Worth a shot – CM2K Nov 11 '15 at 15:37
  • @CM2K your solution waste a ressource because you create a temporary table which is not the best solution – CodeNotFound Nov 11 '15 at 15:39
  • @CodeNotFound True, but since I don't have any experience with Linq i simply suggested something which may work and solve the problem. Maybe the OP didn't think of this, happens – CM2K Nov 11 '15 at 15:40
0
var grouped = from d in db.MyTable.AsEnumerable()
              group d by new {
      User = d.User, 
      Date=d.Date.HasValue ? d.Date.Value.Date : (DateTime?)null} into g
              select new {User=g.Key.User, Date=g.Key.Date, Count=g.Count()};

Sooner or later, someone would say that this is not server side grouping and would suffer from performance and they would be right. Without Enumerable it is serverside but at the cost of another call per group, so here is another way:

public class MyResult
{
  public string User {get;set;}
  public DateTime? Date {get;set;}
  public int Count {get;set;}
}

var grouped = db.ExecuteQuery<MyResult>(@"select [User], 
  Cast([Date] as Date) as [Date],
  Count(*) as [Count]
from myTable
group by [user], Cast([Date] as Date)");

EDIT: I don't know why I thought the other way before, this would just work serverside and do it, AsEnumerable() was not needed:

var grouped = from d in db.MyTable
              group d by new {
      User = d.User, 
      Date=d.Date.HasValue ? d.Date.Value.Date : (DateTime?)null} into g
  select new {User=g.Key.User, Date=g.Key.Date, Count=g.Count()};
Cetin Basoz
  • 22,495
  • 3
  • 31
  • 39
0

For Linq Query just do the following: (you need to import using System.Data.Entity.SqlServer namespace.

Execute this linq query all calculations are done on the server database. Notice that Table1s represents the DbSet for Table1 and context is your DbContext instance.

var query = from item in context.Table1s
    group item by new
    {
       item.User, 
       Year = SqlFunctions.DatePart("yyyy", item.Date), 
       Month = SqlFunctions.DatePart("mm", item.Date), 
       Day = SqlFunctions.DatePart("dd", item.Date)
    } into g
    select new { g.Key.User, g.Key.Year, g.Key.Month, g.Key.Day, Count = g.Count() };

Then create the final result like this:

var result = query.ToList().Select(p =>
    new
    {
        p.User,
        Date = new DateTime(p.Year.Value, p.Month.Value, p.Day.Value),
        p.Count
    }).ToList();

Other solution is to create a SQL View that will be used by DbContext to retrive the data you want. The SQL View body must be the SQL your wrote in your question.

EDIT 2 : DbFunctions

Like Cetin Basoz pointed in comments we can use System.Data.Entity.DbFunctions as well. And the code is more cleaner than using SqlFunctions. This will work only with EF 6 and greater. The version using SqlFunctions work with EF 4 and greater.

var query = from item in context.Table1s
    group item by new
    {
        item.User, 
        Date = DbFunctions.TruncateTime(item.Date)
    } into g
    select new { g.Key.User, g.Key.Date, Count = g.Count() };

EDIT 1 : this is specific for Cetin Basoz's answer :

As we all know using AsEnumerable is not efficient for doing what is needed. The second solution he gives us which is :

var grouped = from d in db.MyTable
          group d by new {
  User = d.User, 
  Date=d.Date.HasValue ? d.Date.Value.Date : (DateTime?)null} into g
  select new {User=g.Key.User, Date=g.Key.Date, Count=g.Count()};

This solution just not work because of this :

The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

CodeNotFound
  • 22,153
  • 10
  • 68
  • 69
  • Although this is marked as an answer, did you try this one at all? How would this work with a nullable date column (which is common for a date/Datetime column). Otherwise I could do the original one simply with d,Date.Date and remove the AsEnumerable. – Cetin Basoz Nov 11 '15 at 16:55
  • Thinking about it again, and retesting, I didn't need the AsEnumerable at all and it worked right server side. I don't know why I saw multiple queries sent to server in first test (must be some left over code). – Cetin Basoz Nov 11 '15 at 17:01
  • Just edit your answer then. Stop flooding others posts. This Is not a compétition and explain why you don't need AsEnumerable. Thanks – CodeNotFound Nov 11 '15 at 17:32
  • @CetinBasoz just check my edited answer and we know why your code not work. – CodeNotFound Nov 11 '15 at 18:45
  • That is not a correct explanation. Date is supported by Linq To SQL. If it is not Linq To SQL then why would you use SqlFunctions? Are they suppported by Linq To EF? – Cetin Basoz Nov 11 '15 at 22:12
  • `System.Data.Entity` is all about Linq To Entities. `System.Data.Entity.SqlServer`is all about Linq to Entites specfic for SQL Server. Nothing doing here with Linq TO SQL. SqlFunctions contains methods that can be translated to SQL Server specific functions for EF. – CodeNotFound Nov 11 '15 at 22:14
  • 1
    I mean if you are using SqlFunctions then you are implying that you are using Linq To SQL, no? I didn't know I could use SqlFunctions in EF and against any database. Maybe then you should instead use DbFunctions.TruncateTime(). – Cetin Basoz Nov 11 '15 at 22:16
  • Thanks, I didn't know about DbFunctions which work with EF6 and greater. I updated my answer. – CodeNotFound Nov 11 '15 at 22:48
  • Hmm if EF4 is a concern, then you could use EntityFunctions which later replaced with DbFunctions. – Cetin Basoz Nov 11 '15 at 23:07
  • We can still use SqlFunctions which is SQL Server Specific. Rather EntityFunctions is not. SQlFunctions, EntityFunctions and DbFunctions all work well.DbFunctions will remain but EntityFunctions and SqlFunctions will maybe in the future removed. They are just a wrapper and perform sometimes same things. – CodeNotFound Nov 11 '15 at 23:13