【问题标题】:Getting results based on a timeframe and grouping by month根据时间范围获取结果并按月分组
【发布时间】:2015-08-18 15:47:41
【问题描述】:

我有一个包含许多表的数据库。其中一个表 VersionBuild 包含一个日期列。我使用以下查询获得结果,并且只选择在特定时间范围内出现的记录(例如过去 6 个月)

我使用的代码如下

DateTime startDate = DateTime.Now.AddMonths(-(timeFrame));
var grouped = db.VersionBuilds
                .Where(r => r.product_id == id && r.date > startDate)
                .GroupBy(r => new { r.date.Year, r.date.Month })
                .Select(r => new { 
                    month = getMonthName(r.Key.Month), 
                    totalIssues = r.Sum(zz => zz.AcrolinxReport.total_issues) 
                });
return grouped;

代码的一个问题是,如果没有特定月份的记录,它会忽略它。我在图表中显示返回的信息,因此这会在数据中留下空白。例如,如果我在 5 月和 6 月有记录,它将返回 5 月和 6 月的数据,但我想要的是返回指定时间范围内所有月份的数据,无论是否有任何数据。

【问题讨论】:

  • 检查出数据库的日期。我认为这是 mysql 中的 Unix 时间
  • 对不起,我的错误是这个数据库使用的是 SQL Server 2008 R2,而不是 MySql
  • 在我看来,您要么需要提前几个月通过并执行一些等效的联接(可能不是实际联接),要么在查询后处理结果。我会做后者。
  • 检索数据后,您可以使用 for 循环或其他方式遍历并插入缺失的月份

标签: c# linq sql-server-2008


【解决方案1】:

我相信这对你有用。没有数据很难测试,但我认为你应该没有任何问题。

// Assume 'timeframe' is a positive integer.

// Get the start date.
DateTime startDate = DateTime.Now.AddMonths(-timeframe);

// Generate a list of months (year and month, actually) beginning 
// with the month of 'startDate'.
var months =
    Enumerable
    .Range(0, timeframe)
    .Select(x => startDate.AddMonths(x))
    .Select(x => new { x.Year, x.Month });

// Create builds query.
var builds =
    db.VersionBuilds
    .Where(r => r.product_id == id && r.date > startDate)
    .GroupBy(r => new { r.date.Year, r.date.Month })
    .Select(r => new { 
        Month = r.Key.Month,
        Year = r.Key.Year,
        TotalIssues = r.Sum(zz => zz.AcrolinxReport.total_issues));

// Join 'months' on 'builds'
var grouped =
    months
    .GroupJoin(
        builds.AsEnumerable(),
        date => date,
        build => new { build.Year, build.Month },
        (date, buildGroup) => new { 
            date.Year, 
            date.Month, 
            TotalIssues = buildGroup.Sum(x => x.TotalIssues) })
    .OrderBy(x => x.Year)
    .ThenBy(x => x.Month)
    .Select(x => new { Month = getMonth(x.Month), x.TotalIssues });

【讨论】:

    【解决方案2】:

    你可以试试这样的:

    首先,我们创建一个包含给定时间范围内所有月份的列表 例如,如果我们现在运行它并将 timeFrame 设置为 3,那么 该列表将包含以下日期时间

    • 2015-08-15 ....,
    • 2015-07-15 ....,
    • 2015-06-15

    代码如下:

    var monthsInTimeFrame = new List<DateTime>();
    for(int i = timeFrame; i>=0 ; i--)
    { 
        monthsInTimeFrame.Add(DateTime.Now.AddMonths(-i));
    }
    

    然后你继续以你已经完成的方式获取数据, 但有一个微小的变化。而不是创建一个对象的列表 匿名类型,您创建一个命名类型的对象列表。我选择了模糊的名字Data。你可以选择任何你想要的名字。此外,这种类型还有两个额外的属性,一个是Year,另一个是Month。我们需要它们,以便确定 预期 个月中的特定月份是否在列表中。

    DateTime startDate = DateTime.Now.AddMonths(-(timeFrame));
    var grouped = db.VersionBuilds
                    .Where(r => r.product_id == id && r.date > startDate)
                    .GroupBy(r => new { r.date.Year, r.date.Month })
                    .Select(r => new Data
                    { 
                        Year = r.Key.Name,
                        Month = r.Key.Month,
                        MonthName = getMonthName(r.Key.Month), 
                        TotalIssues = r.Sum(zz => zz.AcrolinxReport.total_issues) 
                    }).ToList();
    

    请注意,我们必须在查询结束时调用ToList,因为下面我们将使用Add 方法来添加缺失的月份。

    最后,我们要遍历monthsInTimeFrame的项目:

    foreach(var month in monthsInTimeFrame)
    {
        // If there isn't any item in the list called
        // grouped with the same year and month of the current month,
        // we have to add a new item in this list       
        if(!grouped.Any(item=>item.Year==month.Year &&
                              item.Month==month.Month)) 
            grouped.Add(new Data
            { 
                Year = month.Year, 
                Month = month.Month,
                MonthName = getMonthName(month.Month), 
                TotalIssues = 0 
            });
    }
    return grouped;
    

    Data 类的定义可能是这样的:

    public class Data
    {
        public int Year { get; set; }
        public int Month { get; set; }
        public string MonthName { get; set; }
        public int TotalIssues { get; set; }
    }
    

    【讨论】:

    • @Alan 不客气,伙计!我很高兴能帮上忙。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    • 2019-01-03
    相关资源
    最近更新 更多