Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Sumar tiempos (https://www.clubdelphi.com/foros/showthread.php?t=95534)

Angel.Matilla 20-01-2022 18:18:23

Sumar tiempos
 
Buenas tardes. A ver si me sé explicar. Tengo esta tabla en FB 2.5:
Código SQL [-]
CREATE TABLE PISTAS (
  DISCO INTEGER NOT NULL,
  ORDEN_DISCO SMALLINT NOT NULL,
  ORDEN_PISTA SMALLINT NOT NULL,
  CANCION CHAR(255),
  INTERPRETE CHAR(60),
  TIEMPO TIME);
Creo que es bastante evidente que se trata de una BB.DD. de discos. Necesito hacer un query que me sume la duración de las pistas; algo así:
Código SQL [-]
SELECT Disco, SUM(Tiempo) FROM Pistas GROUP BY Disco ORDER BY Disco
Pero al porbar en SQL Manager me da este error:
Cita:

Unsuccessful execution caused by a system error that precludes successful execution of subsequent statements.
Dynamic SQL Error.
Expression evaluation not supported.
Argument for SUM in dialect 3 must be numeric.
¿Cómo podría hacer ese tipo de query? ¿Bastaría con cambiar el dialecto de la BB.DD. al hacer la suma?
Ya sé que podría sacar los tres datos (hora, minutos y segundos) por separado:
Código SQL [-]
SELECT Disco, SUM(EXTRACT(HOUR FROM Tiempo)) Hora, SUM(EXTRACT(MINUTE FROM Tiempo)) Minuto, SUM(EXTRACT(SECOND FROM Tiempo)) Segundo
  FROM Pistas
 GROUP BY Disco
 ORDER BY Disco
pero al hacer luego un EncodeTime es muy fácil que dé error porque, por ejemplo, una de las sumas saldría algo así:
Cita:

Disco: 9
Hora: 0
Minuto: 38
Segundo: 711

mamcx 20-01-2022 19:40:08

Ahi tienes que usar es funciones de fecha, no de numero.

Casimiro Notevi 20-01-2022 20:23:33

¿Seguro que es dialecto 3?
¿Has mirado los datos del campo tiempo con isql? Es para ver el valor real que tiene guardado, sin máscaras.

Neftali [Germán.Estévez] 21-01-2022 08:33:54

Yo optaría por guardar internamente los tiempos en segundos (en BD).
Luego a la hora de pintarlos sólo tienes que pasarlos a horas, minutos y segundos. Es una cuestión de visualización.

De esa forma puedes usar la funciones tipo SUM sin problemas.

Angel.Matilla 21-01-2022 10:02:32

Cita:

Empezado por mamcx (Mensaje 545007)
Ahi tienes que usar es funciones de fecha, no de numero.

Efectivamente, pero es que en algún sitio había visto que se podía usar el SUM sobre valores de tiempo.
Cita:

Empezado por Casimiro Notevi (Mensaje 545008)
¿Seguro que es dialecto 3?

La definición de la BB.DD. está puesta así:
Código SQL [-]
Ocio->Connected               = false;
Ocio->DatabaseName            = "Tablas\\Ocio.fdb";
Ocio->SQLDialect              = 3;
Ocio->Params->Clear();
Ocio->Params->Add("USER 'sysdba'");
Ocio->Params->Add("PASSWORD 'masterkey'");
Ocio->Params->Add("PAGE_SIZE 4096");
Ocio->Params->Add("DEFAULT CHARACTER SET ISO8859_1 COLLATION ES_ES_CI_AI");
Ocio->CreateDatabase();
Así que sí, es dialecto 3.
Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 545009)
Yo optaría por guardar internamente los tiempos en segundos (en BD).
Luego a la hora de pintarlos sólo tienes que pasarlos a horas, minutos y segundos. Es una cuestión de visualización.

De esa forma puedes usar la funciones tipo SUM sin problemas.

Es una alternativa que no se me había ocurrido pero te obliga a decodificar el tiempo para poder guardarlo en segundos con lo cual al final tienes el mismo trabajo; he optado por el segundo query de mi mensaje (SUM(EXTRACT(HOUR FROM Tiempo)) Hora) y queda así el código:
Código:

int Hora, Minuto, Segundo;

Query->Close();
Query->SQL->Text = "SELECT Disco, SUM(EXTRACT(HOUR FROM Tiempo)) Hora,
                                  SUM(EXTRACT(MINUTE FROM Tiempo)) Minuto,
                                  SUM(EXTRACT(SECOND FROM Tiempo)) Segundo
                      FROM Pistas GROUP BY Disco ORDER BY Disco";
Query->Open();

for (; !Query->Eof; Query->Next())
{
    Segundo = Query->FieldByName("Segundo")->AsInteger % 60;
    Minuto = Query->FieldByName("Minuto")->AsInteger + (int)Query->FieldByName("Segundo")->AsInteger / 60;
    Hora = Query->FieldByName("Hora")->AsInteger + (int)Query->FieldByName("Minuto")->AsInteger / 60;
    Minuto = Minuto % 60;
    [...]
}

Muchas gracias por todas vuestras sugerencias.

Casimiro Notevi 21-01-2022 10:52:40

Cierto, estaba pensando al revés, con dialecto 3 no puedes sumar.

mamcx 21-01-2022 16:37:09

Cita:

Empezado por Angel.Matilla (Mensaje 545010)
Efectivamente, pero es que en algún sitio había visto que se podía usar el SUM sobre valores de tiempo.

https://firebirdsql.org/refdocs/lang...c-dateadd.html

Calculos de fechas se hacen con funciones de fecha. Siempre.

Casimiro Notevi 21-01-2022 17:11:02

La verdad es que yo me he quedado "pillado" porque no me ha funcionado las pruebas que he hecho, sin embargo:


Cita:

Tipos fecha y hora.
Tabla II.II. Tipos de datos fecha y hora en Firebird
NOMBRE TAMAÑO RANGO/PRECISIÓN DESCRIPCIÓN
DATE 32 bits con signo 01-01-100 a 31-12-9999 Fecha Ejm: 12/10/1977
TIME 32 bits sin signo 0:00:00 a 23:59:59.9999 Hora
TIMESTAMP 64 bits (2x32 bits) 1 jan 100 CE to 28 feb 32768 CE
Incluye la hora y la fecha en dos estructuras de 32 bits
Al estar todos los tipos fecha almacenados como números, es posible, realizar operaciones aritméticas. Así si a un tipo DATE le suma o resta un entero, se obtendrá una nueva fecha con el incremento o decremento en días correspondiente. Si se resta dos fechas, se obtendrá el número de días entre ellas. Si se resta dos horas, se obtendrá el número de segundos entre ellas.

Angel.Matilla 21-01-2022 17:53:49

Cita:

Empezado por Casimiro Notevi (Mensaje 545015)
La verdad es que yo me he quedado "pillado" porque no me ha funcionado las pruebas que he hecho, sin embargo:

Ese tipo de operaciones (sumarle o restarle a una fecha) lo hago con relativa frecuencia, por ejemplo para encontrar cuando vence un recibo a domiciliar, pero con horas no lo había hecho nunca. Y he hecho alguna prueba sobre una tabla que guarda exclusivamente tiempo; por ejemplo:
Código SQL [-]
SELECT Duracion + 1 FROM Titulos WHERE Tipo = 2 AND Disco = 589
El registro original en ese campo tiene guardado el valor 0:40:01, pero el query no devuelve nada; por lo que se ve sobre campos de tiempo no puede hacerse.

Casimiro Notevi 21-01-2022 18:02:43

Por lo visto se puede sumar/restar valores a fechas y horas, y se puede restar fechas y devuelve los días entre ellas, pero lo que no se puede, por lo visto, es sumar fechas ni tampoco horas.

Yo habría jurado que se podía.


La franja horaria es GMT +2. Ahora son las 01:30:40.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi