Ir al contenido


Foto

¿Cómo realizar un for-downto en Firebird?


  • Por favor identifícate para responder
13 respuestas en este tema

#1 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 26 noviembre 2012 - 12:43

Pues necesito realizar una consulta de los ültimos 12 meses a partir de la fecha actual, eso lo puedo hacer utilizando DATEADD(), pero necesito hacer una especie de recorrido "hacia atrás", como un for downto en delphi, pero en firebird creo se utiliza el while, pero no sé como entrarle, a ver si alguien me muestra un ejemplo sencillo sólo para entender su funcionamiento.

Saludos.
  • 0

#2 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 26 noviembre 2012 - 12:59

Buscas algo así??

CREATE OR ALTER PROCEDURE NEW_PROCEDURE 
returns (
    d date)
as
declare variable i integer;
begin
  i = 1;
  while (i < 12) do
  begin
    d = dateadd(i * (-1) month to current_date);
    i = i + 1;
    suspend;
  end
end

  • 0

#3 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 26 noviembre 2012 - 01:12

Muchas gracias cadetill, ya iré a practicarlo. (y)

Saludos.
  • 0

#4 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 27 noviembre 2012 - 09:59

Hice lo siguiente utilizando consultas:

CREATE OR ALTER PROCEDURE LAST_TWELVES_STATS 
returns (
    mes integer,
    totalmes numeric(15,2))
as
declare variable i integer;
BEGIN
    I = 1;
    while (I < 12) do
      BEGIN
        select sum(DESP_CANT), EXTRACT(MONTH FROM DESP_FECHA) from despachos
        where EXTRACT(MONTH FROM DESP_FECHA) = EXTRACT(MONTH FROM dateadd(i * (-1) MONTH TO CURRENT_DATE)) INTO :totalmes, :mes;
        i = i + 1;
        suspend;
    END
END


Me da error con la variable i en el where :(.

Saludos.
  • 0

#5 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 27 noviembre 2012 - 10:37

Creo que el problema no es el "where" ni la "i", sino la sentencia SQL en sí. Tienes una función de agrupación (un Sum) pero no tienes ningún "group by" ;-)

Nos leemos
  • 0

#6 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 27 noviembre 2012 - 11:01

Gracias por responder Xavier, pero agregué el Group BY y aún así marca el error en el "i" del where:

BEGIN
    I = 1;
    while (I < 12) do
      BEGIN
        SELECT SUM(DESP_CANT), EXTRACT(MONTH FROM DESP_FECHA) FROM despachos
        WHERE EXTRACT(MONTH FROM DESP_FECHA) = EXTRACT(MONTH FROM dateadd(i * (-1) MONTH TO CURRENT_DATE))
        GROUP BY EXTRACT(MONTH FROM DESP_FECHA)
        INTO :totalmes, :mes;
        i = i + 1;
        suspend;
    END
END


Error:



delphi
  1. Column does not belong to referenced table.
  2. Dynamic SQL Error.
  3. SQL error code = -206.
  4. Column unknown.
  5. I.
  6. At line 11, column 75.



Saludos.
  • 0

#7 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 27 noviembre 2012 - 11:15

Al estar dentro de una sentencia SQL, el compilador interpreta la "i" como un campo de la tabla consultada. Para que lo interprete como una variable debes anteponerle ":"

Nos leemos
  • 0

#8 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 27 noviembre 2012 - 11:26

Muchas Gracias Xavier, ahora sí se ejecutó, lo malo es que no me suma los últimos 12 meses de este año sino de los 5 años de información que tengo :D  :|
  • 0

#9 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 27 noviembre 2012 - 11:35

Bueno, eso ya es cosa del filtro que le pones a la sentencia SQL. Si te fijas sólo comparas el mes. Deberías comparar también el año si sólo quieres un año jejejeje

Nos leemos
  • 0

#10 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 27 noviembre 2012 - 12:14

jejeje, dicen por ahí que 4 ojos ven mejor que 2 :p, ya me lanza los datos correctos, pero sí que tarda el asunto  :| (de 10 a 20 segundos), el procedimiento quedó así:

CREATE OR ALTER PROCEDURE LAST_TWELVES_STATS 
returns (
    mes integer,
    totalmes numeric(15,2))
as
declare variable i integer;
BEGIN
    I = 1;
    while (I < 12) do
      BEGIN
        select sum(DESP_CANT), EXTRACT(MONTH FROM DESP_FECHA) from despachos
        where EXTRACT(MONTH FROM DESP_FECHA) || EXTRACT(Year FROM DESP_FECHA) = EXTRACT(MONTH FROM dateadd(:i * (-1) MONTH TO CURRENT_DATE)) || EXTRACT(YEAR FROM dateadd(:i * (-1) MONTH TO CURRENT_DATE))
        and DESP_ESTADO = 1 AND DESP_COMB = 2
        GROUP BY Extract(month from desp_fecha) INTO :totalmes, :mes;
        i = i + 1;
        suspend;
    END
END


¿Habrá una forma de agilizarlo?.

Saludos.
  • 0

#11 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 27 noviembre 2012 - 02:33

Para acelerarlo, lo que tienes que hacer es definir un índice en la tabla "despachos" por los campos DESP_FECHA, DESP_ESTADO y DESP_COMB, algo como

CREATE INDEX NombreIndice
ON despachos (DESP_FECHA,DESP_ESTADO,DESP_COMB)


No obstante tendremos un problema. Cuando se usa la función EXTRACT, ese campo no se tiene en cuenta en el momento de indexar. Así pues, lo que hay que hacer es sustituir la función EXTRACT por un between de fechas (entre el día 1 del mes y el último día del mes). Así pues, podríamos hacer algo así

CREATE OR ALTER PROCEDURE LAST_TWELVES_STATS 
returns (
    mes integer,
    totalmes numeric(15,2))
as
declare variable i integer;
declare variable m integer;
declare variable y integer;
declare variable fini date;
declare variable ffin date;
begin
  i = 1;
  while (i < 12) do
  begin
    /* la idea es acelerar la consulta. Para ello tenemos que definir un índice
      por todos los campos que forman la WHERE. Dado que si se usa la función
      EXTRACT ya no se contemplaría un índice establecido por el campo fecha,
      tenemos que buscar el primer y último día del mes que queremos controlar
      para así poder usar el BETWEEN.
      Cómo no existe una función en PSQL que nos dé el último día del mes, lo
      que haremos es posicionarnos en el mes+1, coger el día 1 de ese mes y
      restarle 1 */

    /* restamos los meses que toquen a current_date menos 1 para saber el mes que toca+1 */
    fini = dateadd((i-1) * (-1) month to current_date);

    /* sacamos mes y año de ese mes */
    m = extract(month from fini);
    y = extract(year from fini);

    /* sacamos último día del mes que queremos => (1/mes+1/año)-1*/
    ffin = cast(y || '-' || m || '-01' as date) - 1;

    /* sacamos mes y año del mes correcto */
    m = extract(month from ffin);
    y = extract(year from ffin);

    /* sacamos primer día del mes correcto */
    fini = cast(y || '-' || m || '-01' as date);

    /* inicializamos variables por si la sentencia SQL no devuelve valores */
    totalmes = 0;
    mes = 0;

    /* lanzamos sentencia SQL */
    SELECT SUM(DESP_CANT), EXTRACT(MONTH FROM DESP_FECHA)
    FROM despachos
    where
      DESP_FECHA between :fini and :ffin and
      DESP_ESTADO = 1 and DESP_COMB = 2
    group by 2
    into :totalmes, :mes;

    i = i + 1;

    suspend;
  end
end


Espero te sirva
  • 0

#12 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 28 noviembre 2012 - 07:18

¡wow!, ahora sí me lanza los datos casi instantaneo, ¡Muchíssimas gracias cadetill!!  (y), doy pot resuelto el tema.

Saludos.
  • 0

#13 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 28 noviembre 2012 - 11:15

Saludos.

A partir de la versión 2 de Firebird es posible crear indices en expresiones.

Con esto es posible que evites el tener que modificar el SP o si ya lo hiciste, para algún SELECT no tendrías que andar rompiéndote la cabeza.

Info
  • 0

#14 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 28 noviembre 2012 - 12:44

Cierto Rolphy, esa fue mi primera opción, lo que pasa es que no vi cómo hacer la expresión para que me cogiera no sólo el extract, sino también los otros 2 campos necesarios para el índice ya que, como dice la documentación, o lo haces por columnas o por una expresión
  • 0




IP.Board spam blocked by CleanTalk.