2011-03-10 11 views
7

La sintaxis de mi consulta es buena, pero no la salida y es realmente extraño.declaración groupby LINQ con la clave

I tienen la siguiente tabla:

| AppointID | UserID | AppointSet | AppointResolved | AppointStatus | AppointmentDatetime 
|  1  | 1 | 3/1/2011 | 3/1/2011  |  1   |  3/15/2011 
|  2  | 1 | 3/2/2011 | 3/5/2011  |  4   |  3/16/2011 
|  3  | 1 | 3/2/2011 | 3/11/2011  |  2   |  3/11/2011 
|  4  | 1 | 3/3/2011 | 3/7/2011  |  3   |  3/25/2011 

ApponintStatus es un byte donde 1 es para el grupo, 2 es para asistieron, 3 es para reprogramada y 4 es para cancelados. AppointDatetime es la fecha para la cual se establece la cita.

Lo que intento hacer es crear la siguiente salida que cuente la actividad por día.

| Date  | Set | Attended | Rescheduled | Cancelled | 
| 3/1/2011 | 1 |    |     |    | 
| 3/2/2011 | 2 |    |     |    | 
| 3/3/2011 | 1 |    |     |    | 
| 3/5/2011 |   |    |     |  1  | 
| 3/7/2011 |   |  1  |     |    | 
| 3/11/2011 |   |    |  1  |    | 

Esto es lo que tengo hasta ahora. TheDate es una fecha dentro del mes que estoy preguntando por (es decir, pasar 4 de marzo y debe devolver la tabla de marzo)

var r = from appnt in MyDC.LeadsAppointments 
     where appnt.UserID == TheUserID 
     where (appnt.AppointResolved.Year == TheDate.Year && appnt.AppointResolved.Month == TheDate.Month) || 
     (appnt.AppointSet.Year == TheDate.Year && appnt.AppointSet.Month == TheDate.Month) 
     group appnt by appnt.AppointResolved.Date into daygroups 
     select new ViewMonthlyActivityModel() 
     { 
      ViewDate = (from d in daygroups 
         select daygroups.Key.Date).First(), // Problem here: need to get dates for instances where an appointment is set but none are resolved 

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

      CountAttendedOnDay = (from c in daygroups 
            where c.AppointResolved.Date == daygroups.Key.Date 
            where c.AppointStatus == 2 
            select c.AppointID).Count(), 

Uno de los problemas es que CountTotalSetOnDay está regresando sólo el recuento de las que se especifican y resuelto el mismo día; el otro problema es que ViewDate necesita devolver todas las fechas: hay fechas en las que no hay citas programadas, pero se atienden citas, reprogramadas o canceladas, y viceversa, hay fechas en las que se establecen citas pero ninguna se resuelve.

Por ahora estoy ejecutando esto con 2 consultas y uniendo los resultados: una consulta devuelve las citas establecidas y la otra devuelve las citas resueltas. Sin embargo, todavía estoy atrapado en la solución con una consulta en una sola lectura.

¿Alguna sugerencia?

Gracias.

Respuesta

0

Creo que la solución con 2 consultas de lectura funciona bien y se mantendrá en pie por ahora.

1

Usted está agrupando por AppointResolved.Date.

Por lo tanto, para cada entrada en grupos de días, daygroups.Key == AppointResolved.Date, y c.AppointSet.Date == daygroups.Key donde la cláusula solo le proporcionará todas las entradas donde la cita se estableció el mismo día como fue resuelto

Me parece que si quiere lograr su objetivo declarado, tendrá que enumerar todas las fechas mencionadas en CUALQUIERA de los campos de su tabla y contarlas.

Por ejemplo, considere:

var appointmentsTaken = (from appnt in GoyaDC.LeadsAppointments 
         where ... // your filters 
         group appnt by appnt.AppointSet.Date into daysset 
         select { Date = daysset.Key Count = daysset.Count() } 

Esto debe darle una lista de las fechas en que las citas en conjunto, y para cada uno, cuántos de ellos.

+0

Sí, ese es el problema en el que estoy atascado. Y, también habrá casos en los que haya una fecha para la cual haya una cita establecida pero no se haya resuelto ninguna cita. – frenchie

+0

Esto es confuso; ¿A dónde va este var appointmentTaken? – frenchie

+0

Es solo un ejemplo para mostrarle cómo obtener la columna 'Establecer' de las entradas de su tabla. Si hace lo mismo para cada fecha y cada campo requerido en su tabla de resultados, debe tener toda la información que necesita para cumplir su objetivo. – tugudum

2

Debe agrupar utilizando tanto la fecha de configuración como la fecha de resolución. Esto podría lograrse fácilmente agregando otra cláusula from haciendo una combinación cruzada con el conjunto de fechas y agrupando por esas fechas.

La siguiente consulta se basa en una consulta LINQ to Objects. LINQ to SQL no es compatible con este tipo de consulta, por lo que deberá decidir si desea usar esto, que se ejecuta en la máquina cliente o en el servidor.

const byte statusAttended = 2; 
const byte statusRescheduled = 3; 
const byte statusCancelled = 4; 
var query = from a in MyDC.LeadsAppointments.AsEnumerable() 
      from date in new[] { a.AppointSet.Date, a.AppointResolved.Date } 
      where a.UserID == TheUserID 
       && date.Year == TheDate.Year 
       && date.Month == TheDate.Month 
      group a by date into g 
      orderby g.Key 
      let set = g.Distinct().ToList() 
      select new ViewMonthlyActivityModel 
      { 
       ViewDate = g.Key, 
       CountTotalSetOnDay = 
        set.Count(a => a.AppointSet.Date == g.Key), 
       CountTotalAttendedOnDay = 
        set.Count(a => a.AppointResolved.Date == g.Key 
           && a.AppointStatus == statusAttended), 
       CountTotalRescheduledOnDay = 
        set.Count(a => a.AppointResolved.Date == g.Key 
           && a.AppointStatus == statusRescheduled), 
       CountTotalCancelledOnDay = 
        set.Count(a => a.AppointResolved.Date == g.Key 
           && a.AppointStatus == statusCancelled), 
      }; 

lo contrario de una solución completamente LINQ a SQL (no la más limpia) que debería funcionar, puede probar esto. Puede haber una forma más agradable de hacerlo, pero no lo sé.

const byte statusAttended = 2; 
const byte statusRescheduled = 3; 
const byte statusCancelled = 4; 
var query = from a in MyDC.LeadsAppointments 
      let setDate = from aa in MyDC.LeadsAppointments 
          where aa.AppointID == a.AppointID 
          select aa.AppointSet.Date 
      let resolvedDate = from aa in MyDC.LeadsAppointments 
           where aa.AppointID == a.AppointID 
           select aa.AppointResolved.Date 
      from date in setDate.Concat(resolvedDate) 
      where a.UserID == TheUserID 
       && date.Year == TheDate.Year 
       && date.Month == TheDate.Month 
      group a by date into g 
      orderby g.Key 
      let set = g.Distinct() 
      select new ViewMonthlyActivityModel 
      { 
       ViewDate = g.Key, 
       CountTotalSetOnDay = 
        set.Count(a => a.AppointSet.Date == g.Key), 
       CountTotalAttendedOnDay = 
        set.Count(a => a.AppointResolved.Date == g.Key 
           && a.AppointStatus == statusAttended), 
       CountTotalRescheduledOnDay = 
        set.Count(a => a.AppointResolved.Date == g.Key 
           && a.AppointStatus == statusRescheduled), 
       CountTotalCancelledOnDay = 
        set.Count(a => a.AppointResolved.Date == g.Key 
           && a.AppointStatus == statusCancelled), 
      }; 
+0

Lo probé y lo volví a probar, pero no devolvía los resultados correctos con datos ficticios. No sé por qué. – frenchie

+0

@frenchie: ¿Qué no está bien sobre cualquiera de estos? Con los datos de muestra, coincide con la salida (con las fechas atendidas y reprogramadas intercambiadas). ¿Hay casos que dejaste fuera? –

+0

No sé por qué no funciona, pero cuando pruebo el resultado de la consulta con los datos de muestra, los resultados son diferentes. Por ejemplo, en CountTotalSetDay, todos mis datos de muestra están diseñados para mostrar un conteo de 16 por cada día y con esta consulta recibo un recuento de 40 por cada día. La consulta que reuní funciona bien. Primero obtiene todo el conjunto, luego todos los demás casos, y luego combina ambos con una consulta de linq a objeto. Sí, hace 2 lecturas, pero por el momento voy a dejarlo así. Su código muestra cómo funciona la declaración "let" y eso me ayudó para otra cosa. Gracias. – frenchie