【问题标题】:Linq-to-SQL group by date-periods depending on a parameter (daily, Monthly....)Linq-to-SQL 根据参数按日期周期分组(每日、每月 ....)
【发布时间】:2012-02-20 11:48:03
【问题描述】:

我正在尝试创建一个返回日期分组结果的 Linq to SQL 查询。挑战在于每天/每周/每月/每季度分组取决于一个可枚举的参数(周期性)。下面是我当前的 Linq to SQL 查询:

var TotalGroupedInvoices = from c in entidades.InvoicesView
                     group c by (periodo == periodicity.Daily) ? c.InvoiceDate.Date :
                                      period == periodicity.Weekly?     c.InvoiceDate.Date.AddDays(-(double)c.InvoiceDate.DayOfWeek) :
                                      period == periodicity.Monthly? new DateTime(c.InvoiceDate.Year,c.InvoiceDate.Month ,1) :
                                      period == periodicity.Quarterly? new DateTime(c.InvoiceDate.Year, c.InvoiceDate.Month - (c.InvoiceDate.Month % 3) +1, 1) :
                                      period == periodicity.Anual ? new DateTime(c.InvoiceDate.Year, 1, 1) : inicio into Periods
                     select new
                     {

                         period = Periods.Key,
                         Total = Periodos.Sum(c => c.Total)
                     };

为了澄清,看一下季度期间的代码片段:

period == periodicity.Quarterly? new DateTime(c.InvoiceDate.Year, c.InvoiceDate.Month - (c.InvoiceDate.Month % 3) +1, 1)

因此,对于第一季度的日期,例如:2012 年 1 月 12 日、2012 年 1 月 15 日或 2012 年 3 月/20 日,我将所有这些日期分组在第一季度开始:2012 年 1 月 1 日,所以它是有效的正如预期的那样。

首先我想知道查询效率。你怎么看待这件事?也许最好将整数转换为 SQL Server 效率并在客户端上重新转换为日期周期,但我不确定这一点。

另一方面,每周组将每周的日期分组到每周的第一个星期日:

period == periodicity.Weekly? c.InvoiceDate.Date.AddDays(-(double)c.InvoiceDate.DayOfWeek)

...但这对我来说是不正确的,因为我来自西班牙,每周从星期一开始。我如何修复周组以考虑到这一点?

所以,总结一下:

  • 这个 Linq to SQL 查询效率怎么样?
  • 如果考虑从周一到周日的周数,我如何每周按此分组?

非常感谢! PD:对不起我的英语水平。

【问题讨论】:

    标签: c# linq-to-sql


    【解决方案1】:

    要回答第一部分,您并不想将枚举值传输到数据库中并让它决定使用哪个代码分支。您拥有在本地做出决定所需的所有信息。

    Expression<Func<InvoicesView, DateTime>> groupingExpr = c => c.InvoiceDate.Date;
    
    if (period == periodicity.Weekly)
    {
      groupingExpr = c => c.InvoiceDate.Date.AddDays(-(double)c.InvoiceDate.DayOfWeek);
    }
    else if (period == periodicity.Monthly)
    {
      groupingExpr = c => new DateTime(c.InvoiceDate.Year,c.InvoiceDate.Month ,1);
    }
    else if (period == periodicity.Quarterly)
    {
      groupingExpr = c => new DateTime(c.InvoiceDate.Year, c.InvoiceDate.Month - (c.InvoiceDate.Month % 3) +1, 1);
    }
    else if (period == periodicity.Anual
    {
      groupingExpr = c => new DateTime(c.InvoiceDate.Year, 1, 1);
    }
    
    
    var TotalGroupedInvoices = entidades.InvoicesView 
      .GroupBy(groupingExpr)
      .Select(grouped => new {
        period = grouped.Key,
        Total = grouped.Sum(c => c.Total)   
      });
    

    这是我能做的最好的混合 groupingExpr 和查询理解语法:

    var TotalGroupedInvoices = from grouped in entidades.InvoicesView.GroupBy(groupingExpr)
      select new {
        period = grouped.Key,
        Total = grouped.Sum(c => c.Total)   
      };
    

    【讨论】:

    • 谢谢,我是 Linq-to-SQL 的新手,没有注意到我的代码和你的代码之间的差异,我将使用 LinqPad 工具尝试您的代码并研究差异。我将在几个小时后返回并将任何疑问或设置发布为已接受的答案。谢谢!
    • @FranCD 我将更改代码以使差异更加清晰。您可能需要在调试器中检查 groupingExpr。
    • 嗨,David,新代码非常清晰,而且正如您所说,使用您的方法生成的 SQL 更短。我想知道是否可以使用 groupingExpression 作为用理解语法编写的 Linq 查询的一部分(作为一个菜鸟,这种语法似乎是最清楚的)。谢谢!
    【解决方案2】:

    要回答第二部分,您只需要做一些“日”算术。您可以内联或作为单独的函数(例如扩展方法)执行此操作:

    public static DateTime FirstDayOfWeek (this DateTime date)  
    {  
      double offset = (date.DayOfWeek == DayOfWeek.Sunday) ? -6 : (DayOfWeek.Monday - date.DayOfWeek);  
      return date.AddDays(offset);  
    }
    

    然后在你的 LINQ 中:

    period == periodicity.Weekly ? c.InvoiceDate.FirstDayOfWeek
    

    但是,鉴于您是从 SQL 中检索它,您可能只想查看那里的日期函数,例如 DATEPART 并在查询中返回它们

    【讨论】:

    • 非常感谢,我会在几个小时内尝试此解决方案,并将任何疑问或设置发布为已接受的答案。
    • 太棒了!请注意,我没有声称要回答您问题的第一部分 - 我会尝试不同的方法来查看性能。为了便于阅读,我会考虑使用单独的函数来计算代表性期间日期
    • 由于我正在编写Linq-to-SQL,因此您的方法存在问题:方法'System.DateTime FirstDayOfWeek(System.DateTime)'不支持SQL转换。那么,是否有可能另一种解决方法?谢谢
    • 对于 LINQ to SQL,看起来你必须内联(我只在 LINQ to 对象上测试过)。见stackoverflow.com/questions/609596/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    • 2017-09-03
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    相关资源
    最近更新 更多