SQL EMA als Funktion erstellen und berechnen, Metabase zeigt aber einfach nur eine gerade Linie

Status
Für weitere Antworten geschlossen.

Judas-Is

Banned
Registriert
Dez. 2025
Beiträge
3
Vielleicht könnte mir jemand helfen. Ich möchte den EMA über die USD-Werte der letzten 31 Tage einer MySQL-Tabelle berechnen. An sich funktioniert es auch ganz gut, aber Metabase zeigt einfach nur eine gerade Linie mit dem Durchschnittswert an. Außerdem ist es nicht gerade performant. Ich vermute, die Komplexität beträgt schon n*n nur für eine Anfrage. Spielen dabei möglicherweise Anfragetimeouts oder die Limits eine Rolle?

Hier ist mein Script:

SQL:
drop function if exists Calc_EMA_1;
DELIMITER $$
create function Calc_EMA_1(p_datum datetime, alpha decimal)
RETURNS decimal(12,2)
DETERMINISTIC
begin
  DECLARE ema decimal;
  DECLARE state decimal DEFAULT null;
  DECLARE inval decimal;
 
  DECLARE cursor_List_isdone BOOLEAN DEFAULT FALSE;
  DECLARE cursor_List CURSOR FOR
      SELECT usd
      FROM book1
      WHERE typ = 'b' AND NOT is_old
        AND datum <= p_datum
      ORDER BY datum ASC;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET cursor_List_isdone = TRUE;
 
  OPEN cursor_List;
  loop_List: LOOP
      FETCH cursor_List INTO inval;
      IF cursor_List_isdone THEN
         LEAVE loop_List;
      END IF;
      
      if state is null then
        set ema = inval;
      else
        set ema = alpha * inval + (1-alpha) * state;
      end if;
      
      set state = inval;
  END LOOP loop_List;
  CLOSE cursor_List;
 
  return ema;
end $$
DELIMITER ;

SELECT * FROM information_schema.routines;

drop view if exists book1_31d_ema;
create view book1_31d_ema as
  select *, Calc_EMA_1(datum, 0.5) as usd_ema from book1 where typ = 'b' and is_old = 0 and datum >= current_timestamp() - interval 31 day order by datum desc;

SELECT * FROM book1_31d_ema LIMIT 50;

Aber Metabase zeigt einfach nur einen festen Durchschnittswert an: (hier als hellblau zu sehen)

1767031854672.png
 
Beim schnellen drüberschauen:

Müsste es nicht anstelle von:

Code:
set state = inval;

Code:
SET state = ema;

sein?
 
Benna schrieb:
Korrekt.

Aber da waren noch mehr Ungereimtheiten:

SQL:
drop function if exists Calc_EMA_1;
DELIMITER $$
create function Calc_EMA_1(p_id int, p_days int, alpha decimal(12,2))
RETURNS decimal(12,2)
DETERMINISTIC
begin
  DECLARE done INT DEFAULT FALSE;
  DECLARE ema decimal(12,2);
  DECLARE state decimal(12,2) DEFAULT null;
  DECLARE inval decimal(12,2);
  DECLARE datum_1 DATETIME;
  DECLARE datum_2 DATETIME;
 
  DECLARE cursor_List CURSOR FOR
      SELECT usd
      FROM book1
      WHERE typ = 'b' AND NOT is_old
        AND datum >= datum_1
        AND datum <= datum_2
      ORDER BY datum ASC;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
 
  SET datum_1 = DATE_SUB(current_timestamp(), INTERVAL p_days DAY);
  SELECT datum INTO datum_2 FROM book1 WHERE id = p_id LIMIT 1;
 
  OPEN cursor_List;
  loop_List: LOOP
      FETCH cursor_List INTO inval;
      IF done THEN
         LEAVE loop_List;
      END IF;
      
      if state is null then
        set ema = inval;
      else
        set ema = (alpha * inval) + ((1.0-alpha) * state);
      end if;
      
      set state = ema;
  END LOOP loop_List;
  CLOSE cursor_List;
 
  return ema;
end$$
DELIMITER ;

SELECT * FROM information_schema.routines;

drop view if exists book1_31d_ema;
create view book1_31d_ema as
  select *, Calc_EMA_1(id, 31, 0.25) as usd_ema from book1 where typ = 'b' and not is_old and datum >= DATE_SUB(current_timestamp(), INTERVAL 31 DAY);

SELECT * FROM book1_31d_ema order by datum desc LIMIT 500;

  • die Deklaration des Cursors und done sollte wie in folgender Reihenfolge sein: https://dev.mysql.com/doc/refman/5.7/en/cursors.html
  • es ist besser, alle decimal-Typen zu begrenzen
  • statt eines Datums sollte die id und Zeitspanne (wie weit zurück...) übergeben werden
  • man braucht nicht immer bei Adam und Eva anfangen... DATE_SUB(current_timestamp(), INTERVAL p_days DAY) genügt
  • die View selbst sollte keine ORDER BY und kein LIMIT haben

Ergebnis:

1767046481291.png
 
Status
Für weitere Antworten geschlossen.
Zurück
Oben