我有一个基于可用数据的数据库程序,会给我一个分组的年度摘要。我正在运行我的测试实例,目前我的数据匹配类似的东西
--------------------------------------------
|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 |
--------------------------------------------
和名为NameElse的BehaviorName将拥有自己的结果集,如
--------------------------------------------
|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
将其分成单独的系列并添加为我的图表系列
答案 0 :(得分:0)
要获取空值,您应使用IEnumberable.DefaultIfEmpty()
进行左连接/* omitted */
group occurence by g.Field<int>("TargetedBehaviorId") into occurences
from o in occurrences.DefaultIfEmpty()
select new
/* omitted */
睡觉后更新
我用它稍微涂了一点,但我没有找到一种优雅的方法来实现这一目标。
如果按TargetBehaviour
分组,那么您只能获得发生某些事情的月份,而DefaultIfEmpty
实际上不会产生影响。如果按Month
进行分组,除非有行为,否则您将获得空出现的所有月份。
我会probalby使用第一个解决方案(从而呈现我的答案:完全不使用DefaultIfEmpty)并使用Union
添加空白月份。无论您使用的是Entity Framework还是Linq-to-Sql,联合都可以提供麻烦(在EF中)并且需要在内存中执行。
因此,对于无关紧要的人,你应该看看 jocull 的答案。
答案 1 :(得分: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
};
});
答案 2 :(得分:-1)
如果你想在SQL端工作,你可以使用SQL程序,一切都有它的优点和缺点,你将要使用的是你自己。