2010-03-11 12 views
5

Tenemos una mesa preparada de la siguiente manera:¿Hay alguna solución establecida para este problema?

|ID|EmployeeID|Date  |Category  |Hours| 
|1 |1   |1/1/2010 |Vacation Earned|2.0 | 
|2 |2   |2/12/2010|Vacation Earned|3.0 | 
|3 |1   |2/4/2010 |Vacation Used |1.0 | 
|4 |2   |5/18/2010|Vacation Earned|2.0 | 
|5 |2   |7/23/2010|Vacation Used |4.0 | 

Las reglas de negocio son:

  • equilibrio vacaciones se calcula vacaciones ganadas vacaciones menos utilizado.
  • Las vacaciones utilizadas siempre se aplican primero a la cantidad ganada de vacaciones más antiguas.

Tenemos que devolver las filas de Vacation Earned que no han sido compensadas por las vacaciones utilizadas. Si las vacaciones utilizadas solo han compensado parte de un registro de vacaciones ganado, debemos devolver ese registro que muestra la diferencia. Por ejemplo, utilizando la tabla anterior, el conjunto de resultados se vería así:

|ID|EmployeeID|Date  |Category  |Hours| 
|1 |1   |1/1/2010 |Vacation Earned|1.0 | 
|4 |2   |5/18/2010|Vacation Earned|1.0 | 

Tenga en cuenta que ficha 2 fue eliminado porque fue completamente compensado por el tiempo usado, pero los registros 1 y 4 se utilizaron sólo parcialmente, por lo que fueron calculado y devuelto como tal.

La única forma en que pensamos hacer esto es obtener todos los registros de vacaciones ganados en una tabla temporal. A continuación, obtenga el total de vacaciones utilizadas y recorra la tabla temporal, elimine el registro más antiguo y restando ese valor del total de vacaciones utilizadas hasta que el total de vacaciones utilizado sea cero. Podríamos limpiarlo cuando las vacaciones restantes sean solo parte del registro de vacaciones más antiguo. Esto nos dejaría solo con los sobresalientes registros de vacaciones ganadas.

Esto funciona, pero es muy ineficiente y funciona mal. Además, el rendimiento simplemente se degradará con el tiempo a medida que se agregan más y más registros.

¿Hay alguna sugerencia para una mejor solución, preferiblemente basada en la configuración? Si no, tendremos que ir con esto.

EDITAR: Esta es una base de datos de proveedores. No podemos modificar la estructura de la tabla de ninguna manera.

Respuesta

2

Lo siguiente debe hacerlo ..

(pero como otros mencionar, la mejor solución sería ajustar las vacaciones restantes a medida que se gastan ..)

select 
    id, employeeid, date, category, 
    case 
    when earned_so_far + hours - total_spent > hours then 
     hours 
    else 
     earned_so_far + hours - total_spent 
    end as hours 
from 
    (
       select 
        id, employeeid, date, category, hours, 
        (
         select 
          isnull(sum(hours),0) 
         from 
          vacations 
         WHERE 
          category = 'Vacation Earned' 
          and 
          date < v.date 
          and 
          employeeid = v.employeeid 
        ) as earned_so_far, 
        (
         select 
          isnull(sum(hours),0) 
         from 
          vacations 
         where 
          category = 'Vacation Used' 
          and 
          employeeid = v.employeeid 
        ) as total_spent 
       from 
        vacations V 
       where category = 'Vacation Earned' 
    ) earned 
where 
    earned_so_far + hours > total_spent 

La lógica es

  1. calcular para cada fila earned, las horas obtuvo hasta ahora
  2. calcular el total de horas utilizadas para este usuario
  3. seleccionar el registro si los total_hours_so_far + horas de este registro - total_spent_hours> 0
+0

y of'course categoría no debe ser texto, pero alguna identificación de otra tabla ... –

+0

Es, acabo de poner el texto en un esfuerzo por hacer el problema más claro. – NYSystemsAnalyst

+1

+1 Intenté resolver este problema, y ​​mi solución fue tan cercana a esta que no vale la pena publicarla. Creo que este es el enfoque correcto. –

0

A medida que pasa el tiempo y se añaden registros, el rendimiento será cada vez peor a menos que haga algo al respecto, como por ejemplo:

  • filas viejas de purga una vez que están "anulados" (por ejemplo, las vacaciones ganadas tiene tenía vacaciones equivalentes hileras usadas y contabilizadas; vacaciones usadas se han usado set vacaciones "caducas" obtenidas como "gastado")
  • Agregue una columna que marque si una fila ha sido "cancelada", e incorpore esta columna en su índices

Seguimiento de cómo los cambios en los datos de esta manera parecen un argumento para modificar las estructuras de su mesa (tienen varias, no solo una), pero eso está fuera del alcance de su problema actual.

En cuanto a la consulta en sí, crearía dos agregados, restar algunos, hacer una subconsulta y, a continuación, unirlo a algún uso inteligente de una de las funciones de clasificación. Huele como una subconsulta correlacionada en algún lugar, también. Puedo intentarlo más tarde (tengo poco tiempo), pero apuesto a que alguien me gana.

+0

debería haber mencionado esto es una base de datos de proveedores (ver texto de arriba). Por lo tanto, no es posible realizar modificaciones en la tabla. – NYSystemsAnalyst

2

Al pensar en el problema, se me ocurrió que la única razón por la que debe preocuparse por cuando se gana vacaciones es si caduca.Y si ese es el caso, la solución más simple es agregar registros de "vacaciones caducadas" a la mesa, de modo que la cantidad de vacaciones restantes para un empleado sea siempre la sum(vacation earned) - (sum(vacation expired) + sum(vacatation used)). Incluso puede mostrar los registros exactos que desea utilizando el último registro caducado de vacaciones como punto de partida para la consulta.

Pero supongo que no es una opción. Para abordar el problema como se le preguntó, tenga en cuenta que cada vez que se encuentre usando una tabla temporal intente poner esos datos en CTE (expresión de tabla común) en su lugar. Lamentablemente, tengo una reunión en este momento y no tengo tiempo para escribir la consulta (quizás más tarde, suena divertido), pero esto debería ayudarte a empezar.

0

Sugeriría modificar la tabla para no perder de vista Balance en su propia columna. De esta forma, solo necesita obtener el registro más reciente para saber dónde se encuentra el empleado.

De esta manera, puede satisfacer el caso simple ("¿Cuánto tiempo de vacaciones tengo?), Al tiempo que es capaz de realizar el engorroso resumen que está buscando en su" Qué partes del tiempo de vacaciones no alinearte con otros bits "informa, que espero sea algo que no necesites muy a menudo.

+0

Debería haber mencionado que esta es una base de datos de proveedores (ver edición arriba). Por lo tanto, no es posible realizar modificaciones en la tabla. – NYSystemsAnalyst

1

Me parece que su conjunto de resultados es confuso e inexacto y puedo ver a los empleados decir: "no, gané 2 horas el 25 de enero, no 1". No es cierto que obtuvieron 1 hora en esa fecha que solo se compensó parcialmente, y no tendrá problemas si decide mostrar de esta manera. Vería una forma diferente de presentar la información. Normalmente, usted presenta una lista de todas las acciones de abandono (obtenidas, caducadas y utilizadas) con un total en la parte inferior o presenta un resumen de las disponibles para su uso y uso.

En más de 30 años en la fuerza de trabajo y habiendo estado bajo diferentes sistemas de cronometraje (además de haber estudiado aún más cuando era analista de gestión), nunca había visto a nadie querer mostrar información de cronometraje de esta manera. Estoy pensando que hay una razón. Si se trata de un requisito, sugiero que se lo repita y explique cómo será confuso leer los datos, y también que sea difícil obtener una solución con un buen rendimiento. No lo aceptaría como un requisito sin tratar de convencer al cliente de que es una mala idea.

+0

Esta es una base de datos de proveedores, ¿no tengo control sobre la estructura de los datos? Este conjunto de resultados no se mostrará a la mayoría de los usuarios. Algunos gerentes quieren saber cuánto tiempo de vacaciones le queda a una persona y las fechas exactas de cuándo se ganó. – NYSystemsAnalyst

Cuestiones relacionadas