2

我有一个基于可用数据的数据库程序,它将给我一个分组的年度总结。使用我正在运行的测试实例,目前我的数据匹配类似的东西

--------------------------------------------
|Month  |Id  |BehaviorName  |Count         |
--------------------------------------------
|1      |NULL|              |0             |
--------------------------------------------
|2      |NULL|              |0             |
--------------------------------------------
|3      |NULL|              |0             |
--------------------------------------------
|4      |NULL|              |0             |
--------------------------------------------
|5      |NULL|              |0             |
--------------------------------------------
|6      |4   |Name1         |2             |
--------------------------------------------
|7      |4   |Name1         |5             |
--------------------------------------------
|7      |3   |NameElse      |7             |
--------------------------------------------
|8      |NULL|              |0             |
--------------------------------------------
|9      |NULL|              |0             |
--------------------------------------------
|10     |NULL|              |0             |
--------------------------------------------
|11     |NULL|              |0             |
--------------------------------------------
|12     |NULL|              |0             |
--------------------------------------------

这是一个非常简单的结果集,但数据可能或多或少复杂。此处输出的数据将与 Telerik RadChart 控件一起用于绘图目的。本质上,我需要做的是获取上面的结果集,并根据指定 ID 的实例数进行镜像,以便可以将其绘制为单独的系列

因此,例如名为 Name1 的 BehaviorName 会有它自己的结果集,例如

--------------------------------------------                
|Month  |Id  |BehaviorName  |Count         |  
--------------------------------------------  
|1      |NULL|              |0             |  
--------------------------------------------  
|2      |NULL|              |0             |  
--------------------------------------------  
|3      |NULL|              |0             |  
--------------------------------------------  
|4      |NULL|              |0             |  
--------------------------------------------  
|5      |NULL|              |0             |  
--------------------------------------------  
|6      |4   |Name1         |2             |  
--------------------------------------------  
|7      |4   |Name1         |5             |  
--------------------------------------------  
|8      |NULL|              |0             |  
--------------------------------------------  
|9      |NULL|              |0             |  
--------------------------------------------  
|10     |NULL|              |0             |  
--------------------------------------------  
|11     |NULL|              |0             |  
--------------------------------------------  
|12     |NULL|              |0             |  
--------------------------------------------  

和 BehaviorName 标题为 NameElse 会有它自己的结果集,比如

--------------------------------------------
|Month  |Id  |BehaviorName  |Count         |
--------------------------------------------
|1      |NULL|              |0             |
--------------------------------------------
|2      |NULL|              |0             |
--------------------------------------------
|3      |NULL|              |0             |
--------------------------------------------
|4      |NULL|              |0             |
--------------------------------------------
|5      |NULL|              |0             |
--------------------------------------------
|6      |NULL|              |0             |
--------------------------------------------
|7      |3   |NameElse      |7             |
--------------------------------------------
|8      |NULL|              |0             |
--------------------------------------------
|9      |NULL|              |0             |
--------------------------------------------
|10     |NULL|              |0             |
--------------------------------------------
|11     |NULL|              |0             |
--------------------------------------------
|12     |NULL|              |0             |
--------------------------------------------

我已决定在我的应用程序中采用单个结果集并尝试通过 LINQ 将其拆分为单独的分组。我的问题是什么是最好的方法?

var series = from occurence in fetched.YearlyTotals.Tables[0].AsEnumerable()
             group occurence by g.Field<int>("TargetedBehaviorId") into occurences
             select new
             {
                 Behavior = occurences.Key,
                 Occurences = from o in occurences
                              select new
                              {
                                 Month = o.Field<int>("Month"),
                                 TargetedBehaviorId = o.Field<int>("TargetedBehaviorId"),
                                 BehaviorName = o.Field<string>("BehaviorName"),
                                 Count = o.Field<int>("Count")
                              }
             };

目前这将忽略任何空字段,但我需要在系列中每个月包含与上述结果集匹配的每个唯一行。目前这个 LINQ 语句只给了我 3 行数据。

此外,如果有一种更简单的方法可以在 SQL 端完成,我也不反对使用它。

更新

我最终使用了这个问题中提到的一些技术的组合。为了清楚起见,我专门创建了一个类来创建我的图表系列项目

private class OccurrenceItem
{
    public int TargetedBehaviorId { get; set; }
    public int Month { get; set; }
    public int Count { get; set; }
    public string BehaviorName { get; set; }

    public OccurrenceItem()
    {

    }

}

//Gets a list of all the months that are returne from the query
//Always returns all 12 months
int[] months = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
var currentBehaviors = from behaviors in fetched.TargetedBehaviors
                       select behaviors;

var emptySet = (from month in months
                from behavior in currentBehaviors
                select new OccurrenceItem
                {
                    Month = month,
                    TargetedBehaviorId = behavior.AssignedBehaviorId,
                    BehaviorName = behavior.Behavior,
                    Count = 0
                }).ToList();

var occurences = (from o in fetched.YearlyTotals.Tables[0].AsEnumerable()
                  select new OccurrenceItem {
                      Month = o.Field<int>("Month"),
                      TargetedBehaviorId = o.Field<int>("TargetedBehaviorId"),
                      BehaviorName = o.Field<string>("BehaviorName"),
                      Count = o.Field<int>("Count")
                  }).ToList();


var merged = occurences.Union(emptySet)
                .GroupBy(x => new {
                    x.Month,
                    x.TargetedBehaviorId,
                    x.BehaviorName,
                }).Select(x => new OccurrenceItem {
                    Month = x.Key.Month,
                    TargetedBehaviorId = x.Key.TargetedBehaviorId,
                    BehaviorName = x.Key.BehaviorName,
                    Count = (from y in x
                            select y.Count).Sum()
                }).OrderBy(x => x.Month);

所有这些语句结合在一起得到了一个List<OccurenceItem>,然后我可以根据它分成单独的系列TargetedBehaviorId并添加为我的图表系列

4

3 回答 3

0

为了更好地理解,使用 IEnumerables 或 IQueryables 分解这些步骤可能是值得的。您可以尝试这样的事情(未经测试,不确定语法)以获得明确定义的月份列表,以确保即使未设置它们也能全部获取。由于没有数据,您可以返回自定义形式的默认值 - 无论您想要什么。

int[] months = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
var series = months.SelectMany(m => {
    var query = from occurence in fetched.YearlyTotals.Tables[0].AsEnumerable()
                where occurence.Field<int>("Month") == m
                select occurence;

    var grouped = query.GroupBy(x => x.Field<int>("TargetedBehaviorId"));

    if(grouped.Any())
    {
        return   from g in grouped
                 select new
                 {
                     Month = m,
                     Behavior = occurences.Key,
                     Occurences = from o in occurences
                                  select new
                                  {
                                     Month = o.Field<int>("Month"),
                                     TargetedBehaviorId = o.Field<int>("TargetedBehaviorId"),
                                     BehaviorName = o.Field<string>("BehaviorName"),
                                     Count = o.Field<int>("Count")
                                  }
                 };
    }

    //Default for the month
    return new {
        Month = m,
        Behavior = int.MinValue,
        Occurences = null
    };
});
于 2013-07-29T20:54:51.170 回答
0

要获取空值,您应该使用IEnumberable.DefaultIfEmpty()进行左连接

/* omitted */
group occurence by g.Field<int>("TargetedBehaviorId") into occurences
from o in occurrences.DefaultIfEmpty()
select new
/* omitted */

睡觉后更新

我用它闲逛了一下,但我没有找到一种优雅的方式来完成这一点。

如果你到TargetBehaviour那时分组,你只会得到发生某些事情的月份,DefaultIfEmpty实际上不会产生影响。如果您按分组,Month您将获得所有空事件的月份,除非有行为。

我很可能会使用第一个解决方案(从而呈现我的答案:完全不使用 DefaultIfEmpty)并使用Union添加空月份。取决于您使用的是实体框架还是 Linq-to-Sql,联合可能会带来麻烦(在 EF 中)并且需要在内存中执行。

因此,很抱歉给您带来不便,您可能应该查看jocull的答案。

于 2013-07-29T19:17:10.837 回答
-1

如果你想在SQL端工作,你可以用SQL过程来做,任何事情都有它的优点和缺点,你要使用什么取决于你。

于 2013-07-29T19:15:38.183 回答