C# linq group by:良好的语法但奇怪的输出

C# linq group by:良好的语法但奇怪的输出,c#,linq,C#,Linq,我的查询语法很好,但输出却不好,这真的很奇怪 我有下表: | AppointID | UserID | AppointSet | AppointAttended | AppointCancelled | AppointRescheduled | AppointmentDatetime | 1 | 1 | 2/15/2011 | | 3/11/2011 | | 3/15/2011 |

我的查询语法很好,但输出却不好,这真的很奇怪

我有下表:

| AppointID | UserID | AppointSet | AppointAttended | AppointCancelled | AppointRescheduled | AppointmentDatetime
|     1     |   1    |  2/15/2011 |                 |   3/11/2011      |                    |  3/15/2011
|     2     |   1    |  2/17/2011 |                 |                  |    3/11/2011       |  3/10/2011
|     3     |   1    |  3/11/2011 |   3/11/2011     |                  |                    |  3/25/2011
|     4     |   1    |  3/10/2011 |                 |   3/11/2011      |                    |  3/11/2011
我想做的是创建以下输出,按天统计活动

|    Date     |   Set   |   Attended   |   Rescheduled   |   Cancelled   |
|  3/10/2011  |    1    |              |                 |               |
|  3/11/2011  |    1    |      1       |       1         |      2        |
请注意,我已将AppointAttended、AppointCancelled和AppointRescheduled字段定义为可空,因为这些字段可能没有日期

查询如下:

var OutputMonthlyActivity = from appnt in MyDC.LeadsAppointments
where appnt.UserID == TheUserID
where (appnt.AppointSet.Year == TheDate.Year && appnt.AppointSet.Month == TheDate.Month) ||
(appnt.AppointAttended.Value.Year == TheDate.Year && appnt.AppointAttended.Value.Month == TheDate.Month) ||
(appnt.AppointRescheduled.Value.Year == TheDate.Year && appnt.AppointRescheduled.Value.Month == TheDate.Month) ||
(appnt.AppointCancelled.Value.Year == TheDate.Year && appnt.AppointCancelled.Value.Month == TheDate.Month)
group appnt by new { SetOn = appnt.AppointSet.Date, ReschedOn = appnt.AppointRescheduled.Value.Date, Attended = appnt.AppointAttended.Value.Date, Cancelled = appnt.AppointCancelled.Value.Date } into daygroups
select new ViewMonthlyActivityModel()
{

ViewDate = (from d in daygroups select d.AppointDatetime.Date).First(),

CountTotalSetOnDay = (from c in daygroups
where c.AppointSet.Date == daygroups.Key.SetOn
select c.AppointID).Count(),

CountAttendedOnDay = (from c in daygroups
where c.AppointAttended.HasValue == true
select c.AppointID).Count(),

CountRescheduledOnDay = (from c in daygroups
where c.AppointRescheduled.HasValue == true
select c.AppointID).Count(),

CountCancelledOnDay = (from c in daygroups
where c.AppointCancelled.HasValue == true
select c.AppointID).Count()

};
date是我传递的一个参数,表示我正在查询的月份中的日期(即3月1日)。问题是,除了3月的所有日期,我还得到了2月最后两天和4月前两天的结果。而且,每天有3排

如果你有任何建议,我将不胜感激


谢谢。

如果您无法更改模式,我将首先对数据进行一些重塑:

var appoinments = MyDC
.LeadsAppointments
.Select(la => new 
    {
        somefields = somedata, //fill in the blanks
        resolveDate =
            la.AppointAttended  ??
            la.AppointCancelled ??
            la.AppointRescheduled,
        resolveReason = 
            la.AppointAttended != null ? 0 : la.AppointCancelled != null ? 1 : 2
    })
现在,我们制作了两个日期与原因的平面表格(0,1,2已参加,取消,重新安排,4已设置)

将以上两个表合并:

var allDates = setDates.Concat(otherDates);
和组:

var groups = allDates.GroupBy(a => new{a.Date, a.Reason});
因此,要查询特定的一天:

groups
    .Where(g => g.Key.Date == someDate)
    .Select(g=> new{g.Key.Reason, Count = g.Key.Count()})
这应该(如果我的完全未测试的代码几乎可以工作)显示4行,每个原因都有计数


这不是您想要的形状,但如果您需要的话,就不难旋转了。

如果您无法更改模式,我将首先对数据进行一点重塑:

var appoinments = MyDC
.LeadsAppointments
.Select(la => new 
    {
        somefields = somedata, //fill in the blanks
        resolveDate =
            la.AppointAttended  ??
            la.AppointCancelled ??
            la.AppointRescheduled,
        resolveReason = 
            la.AppointAttended != null ? 0 : la.AppointCancelled != null ? 1 : 2
    })
现在,我们制作了两个日期与原因的平面表格(0,1,2已参加,取消,重新安排,4已设置)

将以上两个表合并:

var allDates = setDates.Concat(otherDates);
和组:

var groups = allDates.GroupBy(a => new{a.Date, a.Reason});
因此,要查询特定的一天:

groups
    .Where(g => g.Key.Date == someDate)
    .Select(g=> new{g.Key.Reason, Count = g.Key.Count()})
这应该(如果我的完全未测试的代码几乎可以工作)显示4行,每个原因都有计数


不是你想要的形状,但如果你需要的话,旋转也不难。

你可以为每一列生成单独的计数,然后将它们全部连接在一起,就像这样(我只为AppointSet和AppointEnd做了这件事,但剩下的很简单):


您可以为每个列生成单独的计数,然后将它们全部合并在一起,就像这样(我只为AppointSet和AppointEnd做过这样的操作,但其余的都很简单):


问题似乎是您的组有一些匿名对象作为其密钥

您正在按对象对每个约会进行分组:

new { SetOn = appnt.AppointSet.Date, ReschedOn = appnt.AppointRescheduled.Value.Date, Attended = appnt.AppointAttended.Value.Date, Cancelled = appnt.AppointCancelled.Value.Date } into daygroups
相反,您应该按实际键进行分组,例如AppointmentDatetime

事实上,对于你想做的事情,我认为你根本不需要分组

假设以下样本数据:

// First, get all appointments for the following user
var TheUserID = 1;
var appointments = from appointment in Appointments where appointment.UserID == TheUserID select appointment;

// Then, find all unique dates
var uniqueDates = appointments.Select(a => a.AppointSet)
    .Union(appointments.Where(a => a.AppointAttended.HasValue).Select(a => a.AppointAttended.Value))
    .Union(appointments.Where(a => a.AppointCancelled.HasValue).Select(a => a.AppointCancelled.Value))
    .Union(appointments.Where(a => a.AppointRescheduled.HasValue).Select(a => a.AppointRescheduled.Value))
    .Union(appointments.Select(a => a.AppointmentDatetime))
      // Filter by the month/year
    .Where(x => x.Month == TheDate.Month && x.Year == TheDate.Year)
      // Finally, select a new object for each unique date holding the counts
    .Select(x => new {
        Date = x,
        Cancelled = appointments.Where(a => a.AppointCancelled.HasValue && a.AppointCancelled.Value == x).Count(),
        Rescheduled = appointments.Where(a => a.AppointRescheduled.HasValue && a.AppointRescheduled.Value == x).Count(),
        Set = appointments.Where(a => a.AppointSet == x).Count(),
        Attended = appointments.Where(a => a.AppointAttended.HasValue && a.AppointAttended.Value == x).Count()
    });

这将产生以下输出:


这就是您要做的吗?

问题似乎是您的组有一些匿名对象作为其密钥

您正在按对象对每个约会进行分组:

new { SetOn = appnt.AppointSet.Date, ReschedOn = appnt.AppointRescheduled.Value.Date, Attended = appnt.AppointAttended.Value.Date, Cancelled = appnt.AppointCancelled.Value.Date } into daygroups
相反,您应该按实际键进行分组,例如AppointmentDatetime

事实上,对于你想做的事情,我认为你根本不需要分组

假设以下样本数据:

// First, get all appointments for the following user
var TheUserID = 1;
var appointments = from appointment in Appointments where appointment.UserID == TheUserID select appointment;

// Then, find all unique dates
var uniqueDates = appointments.Select(a => a.AppointSet)
    .Union(appointments.Where(a => a.AppointAttended.HasValue).Select(a => a.AppointAttended.Value))
    .Union(appointments.Where(a => a.AppointCancelled.HasValue).Select(a => a.AppointCancelled.Value))
    .Union(appointments.Where(a => a.AppointRescheduled.HasValue).Select(a => a.AppointRescheduled.Value))
    .Union(appointments.Select(a => a.AppointmentDatetime))
      // Filter by the month/year
    .Where(x => x.Month == TheDate.Month && x.Year == TheDate.Year)
      // Finally, select a new object for each unique date holding the counts
    .Select(x => new {
        Date = x,
        Cancelled = appointments.Where(a => a.AppointCancelled.HasValue && a.AppointCancelled.Value == x).Count(),
        Rescheduled = appointments.Where(a => a.AppointRescheduled.HasValue && a.AppointRescheduled.Value == x).Count(),
        Set = appointments.Where(a => a.AppointSet == x).Count(),
        Attended = appointments.Where(a => a.AppointAttended.HasValue && a.AppointAttended.Value == x).Count()
    });

这将产生以下输出:



这就是你想要做的吗?

每一行是否只使用三种结果中的一种(参加、取消、重新安排)?我改变了几件事:每天有三行。Row1=集合和取消列中集合的计数;row2=集合和有人参与列中有人参与的计数;第3行=集合和重新调度列中重新调度的计数。是的,每一行只是结果之一。可能不是你现在需要的,但是如果可能的话,你可以考虑一个模式改变,这3个COL被减少到只有两个,解决方案和解决方案。这将大大减少查询的难度,并将占用更少的空间。想象一下,能够通过理性进行分组。。。诱惑?这是有道理的可能性。目前,我正在寻找解决这个问题的方法,看起来我还没走那么远。它必须与分组保持一致。你的建议听起来很诱人;我在考虑更新在两种模式下的工作方式。我仍然会被困在同一个groupby问题上没有?我会计算所有集合、预定、取消和参加的约会,但分组问题似乎是一样的。每一行是否只使用三种结果中的一种(参加、取消、重新安排)?我改变了几件事:每天有三行。Row1=集合和取消列中集合的计数;row2=集合和有人参与列中有人参与的计数;第3行=集合和重新调度列中重新调度的计数。是的,每一行只是结果之一。可能不是你现在需要的,但是如果可能的话,你可以考虑一个模式改变,这3个COL被减少到只有两个,解决方案和解决方案。这将大大减少查询的难度,并将占用更少的空间。想象一下,能够通过理性进行分组。。。诱惑?这是有道理的可能性。目前,我正在寻找解决这个问题的方法,看起来我还没走那么远。它必须与分组保持一致。你的建议听起来很诱人;我在考虑更新在两种模式下的工作方式。我仍然会被困在同一个groupby问题上没有?我会计算所有预约、预约、取消和有人参加的预约的数量,但分组问题似乎是一样的。改变模式似乎是更好的选择。但是,查询将非常类似。分组会有什么不同?我将复制表并尝试更改模型。现在我正处于设计阶段,所以我可以试试这个,看起来现在做起来可能比在现场应用程序上尝试voodoo更容易;我正在改变模型,但是如果我不能让它与2列选项(resolveDate,resolveStatus)一起工作,那么我将尝试这个。感谢您的研究。是的,如果您可以在模式中获得它,那么您可以为resolveStatus和date列编制索引,以获得更大的加速。好的,我按照您的建议进行了操作