3

我在我的 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))
    };
4

3 回答 3

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(通常是枚举器)的工作方式,只会计算四天加上任何跳过的天数。

于 2012-11-07T19:01:29.480 回答
2

我强烈建议在检索您的行之后编写您的异常代码(本月的最后一个星期五),因为这种逻辑对于 LINQ 语句来说似乎太复杂了。不是检索最后 4 天,而是检索最后 5 天。删除每个相应月份的最后一个星期五。如果仍有 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))
  };
于 2012-11-07T18:43:00.843 回答
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))

于 2012-11-07T20:04:20.060 回答