none
Creacción función calculo de tiempo RRS feed

  • Pregunta

  • Buenas a todos.

    Tengo problemas a la hora de realizar una función que me calcule el tiempo empleado en una tarea específica. Me explico, tengo una tabla tracks donde tengo los atributos codigoTarea, nombreUsuario y fecha. Todos estos atributos son claves para que así sean únicos. La idea es realizar una función que pasandole el codigoTarea te calcule el tiempo invertido en esa tarea. Yo tengo algo parecido realizado en C# y poniendo un atributo nuevo llamado tiempoTotal que lo voy calculando con la función DATEDIFF por cada vez que se crea una tarea nueva en la tabla TRACKS, pero me piden que quite esa columna y lo haga con una función de SQL y claro, llevo varios días dandole vueltas y no consigo sacarlo.

    La idea que tengo es comprobar que el codigoTarea introducido comprobar que la fecha sea menor que la actual y en ese caso comprobar si termina esa tarea y claro, aquí tengo el problema, ya que no se como realizar la consulta esa.

    No sé si me he explicado bien, espero que sí, de todos modos intentaría explicarme mejor en caso de que no esté bien explicado.

     

    Un saludo y muchas gracias.

    martes, 26 de abril de 2011 9:27

Respuestas

  • En primer lugar, esta pregunta no tiene nada que ver con el hilo abierto: deberías haber creado otro hilo donde preguntaras esto. De ese modo, si a alguien le pasa lo mismo que a ti le será más sencillo encontrar la respuesta, si es que finalmente encontramos una que te valga. Por esa razón se debe marcar como respuesta cuando el comentario de alguien soluciona el problema descrito.

    En cualquier caso, volviendo a lo que te ocure, te diré que una cosa es salvar el script que tienes en SSMS y otra ejecutarlo (F5 o la flechita verde). Tú lo que estás haciendo es salvar el script, con lo que en ningún momento estás creando la función en tu base de datos.

    Luego, no tiene sentido ejecutar un UPDATE y devolver un código de retorno en una función escalar, no están pensadas para eso. Lo más lógico es crear un procedimiento almacenado que devuelva un código de retorno (si es que lo necesitas).

    Y por último, no sé qué es lo que pretendes con el bloque de código que comienza por if (fechaFin is null). Primero porque te va a dar un error de sintaxis, y segundo porque si lo que quieres es comprobar que se ha actualizado una fila, no se hace así, sino con (por ejemplo, con @@ROWCOUNT (http://msdn.microsoft.com/es-es/library/ms187316.aspx)

    • Marcado como respuesta Egroj80 miércoles, 27 de abril de 2011 13:59
    miércoles, 27 de abril de 2011 12:29

Todas las respuestas

  • No entiendo muy bien el diseño de la tabla. Desde mi punto de vista, una tarea tiene un inicio y tiene un fin, pero con ese diseño parece que se puede ir almacenando intervalos (o algo similar), ya que nada impide insertar varias veces el mismo código de tarea para el mismo usuario siempre y cuando la fecha sea diferente. ¿Ese es el propósito? Si hay que calcular el tiempo total para cada uno de esos intervalos, la cosa es un poco más complicada.

    Sin embargo, si lo que necesitas es simplemente coger la primera fecha y la última para una tarea y usuarios específicos, y obtener el tiempo que ha pasado, entonces sería más sencillo. Si fuera así, el diseño de la tabla sería erróneo (por lo que te he comentado), por lo que lo primero que habría que hacer es modificarlo.

    Una vez nos aclares esto, podremos responderte mejor

     

     

    martes, 26 de abril de 2011 9:39
  • Te explico el problema más detalladamente, estoy realizando una aplicación que se ejecute en segundo plano al iniciar el ordenador y que sirva para calcular el tiempo invertido en sus tareas. Esta aplicación captura quien inició sesión en el ordenador y lo introduce en la tabla Usuarios.

    Cada usuario se administra individualmente las tareas, es decir, tiene una opción settings donde puede crear una tarea o dar por terminada una tarea. Y cuando crea una tarea se crea un registro en una tabla Tareas con los atributos codigoTarea (campo identity y primary key) nombreTarea (varchar), nombreUsuario (varchar), activa (int donde 0 es que terminó la tarea y 1 si no está terminada). Hasta aquí todo funciona, lo único que además tengo la tabla Tracks, que son los tiempos que invierte cada usuario en sus tareas, esta tabla como comenté tiene los atributos codigoTarea (int y foreign key de tabla Tareas), nombreUsuario (foreign key de usuarios)  y fecha (datetime) y todas son clave para que así sean únicos los registros.

    Cuando el usuario inicia el ordenador, se crea el siguiente registro en TRACKS (1, 'nombre', GETDATE()). Y cada vez que cambien de tarea se genera en TRACKS algo similar, en plan, el codigoTarea que corresponda a la tarea a la que cambie, el nombreUsuario que corresponda y la hora a la que se cambió.

    Yo hice todo esto (con ayuda de este foro) en C# y funciona, pero puse un atributo tiempoTotal en la tabla TRACKS para que así mediante C# cada vez que realizan el cambio de tarea se realiza la siguiente consulta "update tracks set tiempoTotal=(select datediff(second, (select top 1 fecha from tracks order by fecha desc), getdate())) where (tiempoTotal is null) and (codigoTarea=" + codigoEnUso + "); insert into TRACKS (codigoTarea, nombreUsuario, fecha) values (" + codigoFuturo + ",'" + usuario + "', CURRENT_TIMESTAMP);".

    Esta sentencia lo que hace es calcular el tiempoTotal del trabajo en curso y crea un nuevo registro en la tabla TRACKS , dejando el atributo tiempoTotal en NULL.

    Pero lo que se busca es que en vez de usar el atributo tiempoTotal, se pueda lanzar una sentencia en SQL y te calcule el tiempo total del codigoTarea que se introduzca. Si se siguiera mi planteamiento, con una función sumar de tiempoTotal estaría, pero se pide calcular el tiempoTotal de cada intervalo.

    Espero no haber liado más el asunto y agradecería cualquier sugerencia.

    Un saludo.

    martes, 26 de abril de 2011 10:06
  • Dándole vueltas, estoy pensando crear un atributo más que sea fechaFin y que cada vez que se cambie de tarea se inserte de nuevo la fecha y hora actual, así se simplificaría la función, no creeis?? Lo único que si ya me dijeron que no les gustaba mi idea anterior, esta idea me las descarten.

    Pensais que es una buena manera de resolver esta cuestión?

    martes, 26 de abril de 2011 10:41
  • Es que si la tabla TRACKS es donde se registra la fecha de inicio de cada tarea, no veo dónde se especifica cuándo se acaba. ¿Cuando se inicia la siguiente tarea?

    Si es así, sería muchísimo más sencillo si efectivamente almacenaras la fecha de fin, en vez de tener que obtenerla a partir de la fecha de inicio de la siguiente tarea. Es más: podrías tener un campo calculado para tener directamente el tiempo transcurrido entre la fecha de inicio y la fecha de fin de cada tarea. De ese modo, la consulta que te piden sería tan sencillo como sumar ese campo calculado

    martes, 26 de abril de 2011 10:49
  • Lo que propones, es lo que tenía yo, que lo puse un poco más arriba, me refiero a lo del atributo tiempoTotal para así ir teniendo el tiempo que dura cada tarea, calculándolo con la fecha y hora de cuando se cambia la tarea. Pero claro, como habrás notado soy nuevo en esto y me dijeron que esa forma no gustaba que querían hacerlo mediante una función en sql y tomando como fecha fin el inicio de la tarea siguiente (en el caso de que exista) y si no existe con la fecha y hora del momento en que se lanza la función. Y llevo unos días dándole vueltas y estoy cada vez más saturado ya que no lo consigo sacar de otra forma, lo único lo que dije en mi último post de crear el atributo tiempoFin, pero claro, si la primera opción me dijeron que no les gustaba, esta es muy parecida, no crees??

    Un saludo y muchas gracias.

    martes, 26 de abril de 2011 11:03
  • No entiendo porqué no les gusta esa opción, cuando al final es la más eficiente. En fin, en cualquier caso, echa un vistazo a este script a ver si se adapta a lo que necesitas:



    DECLARE @tracks AS TABLE (idTarea INT, usuario VARCHAR(10),  [start_date] DATETIME)


    INSERT @tracks
    VALUES (1, 'U1', '20110426 8:00')
        , (2, 'U1', '20110426 8:15')
        , (3, 'U1', '20110426 9:15')
        , (1, 'U1', '20110426 10:00')   
        , (3, 'U2', '20110426 9:00')
        , (2, 'U2', '20110426 9:45')
        , (3, 'U2', '20110426 10:00')

    ; WITH prev AS
    (
        SELECT  t1.*       
            , DATEDIFF
                (
                    MI
                    , t1.[start_date]
                    , ISNULL
                        (
                            (SELECT MIN(t2.[start_date]) FROM @tracks t2 WHERE t1.idTarea<>t2.idTarea AND t1.usuario=t2.usuario AND t1.[start_date] < t2.[start_date])
                            , GETDATE()
                        )
                ) AS [minutes]   
        FROM @tracks t1
    )       

    SELECT p.idTarea, p.usuario, SUM(p.[minutes]) AS [minutes]
    FROM prev p
    GROUP BY p.idTarea, p.usuario

    martes, 26 de abril de 2011 11:45
  • Muchas gracias por tu aporte. Pero he decidido realizar lo que habiamos hablado al principio, poner un atributo fechaFin en la tabla TRACKS y así luego poder hacer los cálculos que quiera.

    Ahora tengo un pequeño problema, porque como querían que se ejecutaran las cosas por SQL (no entiendo muy bien por qué, la verdad) he creado una función en SQL con SQL Management Express y a la hora de poder usarla no me aparece. En el explorador de objetos, busco mi BBDD y la expando hasta la Programación->Funciones y allí con el botón derecho, selecciono Nueva función con valores escalaras y aquí incluyo mi función:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:       
    -- Create date: 27-04-2011
    -- Description:    Función que finaliza una tarea añadiendo la fecha
    -- =============================================
    CREATE FUNCTION finalizarTarea
    (
        -- Add the parameters for the function here
        @codigo int,
        @usuario varchar(50)
    )
    RETURNS int
    AS
    BEGIN
        -- Declare the return variable here
        DECLARE @Resultado int;

        -- Add the T-SQL statements to compute the return value here
        update tracks set fechaFin=getdate() where codigoTarea=@codigo and fechaInicio=(select top 1 fechaInicio from tracks where codigoTarea=@codigo and nombreUsuario=@usuario order by fechaInicio desc);
       
        if (fechaFin is null)
        begin
            set @Resultado=-1;
        end   
        else
        begin
            set @Resultado=1;
        end
       
        -- Return the result of the function
        RETURN @Resultado

    END
    GO

     

    Al dar a guardar me creo el fichero finalizarTarea.sql pero cuando en una consulta intento acceder a ella no puedo, de echo no se me salva en la carpeta de funciones del explorador de objetos.

    A qué se debe esto?

    Un saludo y muchisimas gracias.

    miércoles, 27 de abril de 2011 11:43
  • En primer lugar, esta pregunta no tiene nada que ver con el hilo abierto: deberías haber creado otro hilo donde preguntaras esto. De ese modo, si a alguien le pasa lo mismo que a ti le será más sencillo encontrar la respuesta, si es que finalmente encontramos una que te valga. Por esa razón se debe marcar como respuesta cuando el comentario de alguien soluciona el problema descrito.

    En cualquier caso, volviendo a lo que te ocure, te diré que una cosa es salvar el script que tienes en SSMS y otra ejecutarlo (F5 o la flechita verde). Tú lo que estás haciendo es salvar el script, con lo que en ningún momento estás creando la función en tu base de datos.

    Luego, no tiene sentido ejecutar un UPDATE y devolver un código de retorno en una función escalar, no están pensadas para eso. Lo más lógico es crear un procedimiento almacenado que devuelva un código de retorno (si es que lo necesitas).

    Y por último, no sé qué es lo que pretendes con el bloque de código que comienza por if (fechaFin is null). Primero porque te va a dar un error de sintaxis, y segundo porque si lo que quieres es comprobar que se ha actualizado una fila, no se hace así, sino con (por ejemplo, con @@ROWCOUNT (http://msdn.microsoft.com/es-es/library/ms187316.aspx)

    • Marcado como respuesta Egroj80 miércoles, 27 de abril de 2011 13:59
    miércoles, 27 de abril de 2011 12:29
  • Muchas gracias!!

    Espero devolver el gran favor ayudando a gente que esté como yo.

    Un saludo.

    miércoles, 27 de abril de 2011 14:00