具有日期的复杂LINQ to SQL查询

时间:2012-11-07 18:39:11

标签: c# sql linq

我正在我的C#项目中使用LINQ to SQL构建一个查询,但是我遇到了一些问题......

我想要做的是选择今天的4个持续日(例如,星期五),所以如果我们在星期五28,我想查询:星期五21,14,7 ...最后四个星期五但不是今天。

这很简单,我已经完成了,但这里是复杂的部分,我想查询我设置的例外情况,例如月末,即每个月的第28天到第1天月,所以让我说我想查询这个(十月,星期五):

今天是星期五26,我想查询:

19,12,5和9月28日(从现在开始的第四个星期五),但正如我所说,28日是月末,所以我需要在9月21日返回,这是最后一个星期五,而不是月末。 ..我和假期有同样的问题,但我想如果我可以处理月末,我可以和他们一起做...

我希望我已经解释好了你理解我想要的东西......这是我的查询,它正在运行,但无法处理异常。 (字段b.day是每天的ID,8表示月末,7表示假期)

var values =
    from b in dc.MyTable
    where // This means end of month
    b.day != 8

    // This triggers to query last 4 days
    && b.date == Convert.ToDateTime(last.ToString("dd/MM/yyy")).AddDays(-28)
    || b.date == Convert.ToDateTime(last.ToString("dd/MM/yyy")).AddDays(-21)
    || b.date == Convert.ToDateTime(last.ToString("dd/MM/yyy")).AddDays(-14)
    || b.date == Convert.ToDateTime(last.ToString("dd/MM/yyy")).AddDays(-7)
    orderby b.id descending
    group b.valor by b.hora_id into hg
    orderby hg.Key descending

    select new
    {
        Key = hg.Key,
        Max avg = System.Convert.ToInt32(hg.Average() + ((hg.Average() * intOkMas) / 100)),
        Min avg = System.Convert.ToInt32(hg.Average() - ((hg.Average() * intOkMenos) / 100))
    };

3 个答案:

答案 0 :(得分:3)

在尝试查询之前,您应该准备要检索的日期列表:

// Get the last four days excluding today on the same weekday
var days = Enumerable.Range(1, 4).Select(i => DateTime.Today.AddDays(i * -7));

然后删除您不想要的任何日子:

// Remove those pesky end-of-month days
days = days.Where(d => d.Day < 28 && d.Day > 1);

当您准备好要检索的日期列表时,才会执行查询:

from b in dc.MyTable
where days.Contains(b.date)  // Translated to SQL: date IN (...)
...

编辑:正如您在评论中提到的,即使您执行了任何过滤,也需要总共四天。因此,只需产生更多天数并采取前四个:

var days = Enumerable.Range(1, int.MaxValue - 1)
                     .Select(i => DateTime.Today.AddDays(i * -7))
                     .Where(d => d.Day < 28 && d.Day > 1)
                     .Take(4);

由于LINQ(通常是枚举器)的工作方式,只计算四天加上任何跳过的天数。

答案 1 :(得分:2)

我强烈建议在检索行之后编写您的异常代码(本月的最后一个星期五),因为这个逻辑对于LINQ语句来说似乎太复杂了。检索最后的4天而不是检索最后4天。删除每个月份的最后一个星期五。如果您仍有5行,请删除最后一行。

<强>更新

var values1 =
  from b in dc.MyTable
  where // This means end of month
  b.day != 8

  // This triggers to query last 4 days
  && b.date == Convert.ToDateTime(last.ToString("dd/MM/yyy")).AddDays(-28)
  || b.date == Convert.ToDateTime(last.ToString("dd/MM/yyy")).AddDays(-21)
  || b.date == Convert.ToDateTime(last.ToString("dd/MM/yyy")).AddDays(-14)
  || b.date == Convert.ToDateTime(last.ToString("dd/MM/yyy")).AddDays(-7)
  orderby b.id descending
  select b;

//Do stuff with values

var values2 = from b in values2
  group b.valor by b.hora_id into hg
  orderby hg.Key descending

  select new
  {
    Key = hg.Key,
    Max avg = System.Convert.ToInt32(hg.Average() + ((hg.Average() * intOkMas) / 100)),
    Min avg = System.Convert.ToInt32(hg.Average() - ((hg.Average() * intOkMenos) / 100))
  };

答案 2 :(得分:2)

在Allon Guralnek的回答基础上,我稍微修改一下:

首先,构建一个无限日期生成器:

public IEnumerable<DateTime> GetDaysLikeMe(DateTime currentDate)
{
    DateTime temp = currentDate;
    while(true)
    {
        temp = temp.AddDays(-7);
        yield return temp;
    }
}

然后,您可以通过限制仅限于符合附加条件的日期来使用延迟执行:

GetDaysLikeMe(DateTime.Now).Where(dt => /* dt meets my criteria */).Take(4)

然后你可以使用这个生成的列表在你的LINQ to SQL中查询,如上面建议的Allon Guralnek:

from b in dc.MyTable
where days.Contains(b.date)  // Translated to SQL: date IN (...)
...

这样做的好处是,您可以为可接受的日期指定其他谓词,并且仍然可以获得至少4个日期。只要确保对无限日期生成器进行一些边界检查,以防一个谓词因任何原因总是返回false(这意味着生成器永远不会退出)。

IE:while(temp > currentDate.AddYears(-1))