Postgres пользовательская агрегатная функция неправильно присваивает значение - PullRequest
1 голос
/ 04 марта 2020

Я довольно новичок в использовании postgresql и попытался написать свою первую определяемую пользователем статистическую функцию. Функция выбора отправляет агрегатной функции последние 20 значений для каждой строки. Функция агрегирования предоставляет начальные значения в виде массива чисел c длины 4 {counter, 'null', down, up}. Нулевое значение - то, где предыдущее значение будет сохранено во время итераций. «Вниз» и «Вверх» являются счетчиками и инициализируются в ноль.

Функция перехода состояния сравнивает текущее значение с предыдущим значением. Если текущее значение выше, то прибавьте разницу. Если ниже, добавьте разницу вниз. Новый массив передается на следующую итерацию, где текущее значение теперь является старым значением (второе значение в массиве), и счетчики для увеличения и уменьшения должны быть переданы.

Проблема, кажется, где-то в Если заявления. Если я увеличу «вниз» или «вверх» на 1, значения, похоже, будут переданы следующей итерации. Если я добавлю разницу «+ diff», значения «вниз» и «вверх» равны нулю и, кажется, никогда не изменятся.

Код, который увеличивает значения только на 1:

CREATE OR REPLACE FUNCTION RSI_STATE(rsi_mat NUMERIC[], close_val numeric)
    RETURNS NUMERIC[]
LANGUAGE plpgsql
AS $$
DECLARE
    downs INTEGER;
    ups INTEGER;
    counter INTEGER;
    cl NUMERIC;
    diff NUMERIC;
BEGIN
    downs := rsi_mat[3];
    ups := rsi_mat[4];
    diff := abs(rsi_mat[2] - close_val);
    RAISE NOTICE 'Beginning Variable seed: %,  close: %,  down: %,  up: %,  diff: %', 
 rsi_mat[2], close_val, downs, ups, diff;

    IF rsi_mat[2] > close_val then
        RAISE NOTICE 'IF LESS down: %,  up: %,  diff: %', downs, ups, diff;
        downs := rsi_mat[3] + 1;
    ELSEIF rsi_mat[2] < close_val then
        RAISE NOTICE 'IF GREATER down: %,  up: %,  diff: %', downs, ups, diff;
        ups := rsi_mat[4] + 1;
    END IF;
    cl := close_val;
    counter := rsi_mat[1] + 1;
    RAISE NOTICE 'End Variable down: %,  up: %,  diff: %', downs, ups, diff;
    RETURN ARRAY[counter,cl, downs, ups];
END;
$$;

CREATE OR REPLACE FUNCTION RSI_FINAL(rsi_mat numeric[])
RETURNS NUMERIC
LANGUAGE PLPGSQL
AS $$
DECLARE
     RS NUMERIC;
BEGIN
     IF rsi_mat[3] = 0 then
         RS = 1000000;
     ELSE
         RS = rsi_mat[4]/rsi_mat[3];
     END IF;
     return (100 - (100/(1 + RS))); 
END;
$$;

SELECT RSI((dailyhist.dhist::json->>'close')::numeric)
OVER(PARTITION BY dailyhist.cusip ORDER BY dailyhist.datetime ROWS BETWEEN 19 PRECEDING AND CURRENT ROW) AS RSI
FROM dailyhist
limit 15

CREATE AGGREGATE RSI(NUMERIC)(
     SFUNC = RSI_STATE,
     STYPE = NUMERIC[],
     FINALFUNC = RSI_FINAL,
     INITCOND = '{1,null,0,0}'
);

Результаты при добавлении 1, которое, по-видимому, обновляет значения на каждой итерации:

NOTICE: Beginning Variable seed: <NULL>, close: 3.37517, down: 0, up: 0, diff: <NULL> 
NOTICE: End Variable down: 0, up: 0, diff: <NULL> 
NOTICE: Beginning Variable seed: 3.37517, close: 3.41684, down: 0, up: 0, diff: 0.04167 
NOTICE: IF GREATER down: 0, up: 0, diff: 0.04167 
NOTICE: End Variable down: 0, up: 1, diff: 0.04167 
NOTICE: Beginning Variable seed: 3.41684, close: 3.396, down: 0, up: 1, diff: 0.02084 
NOTICE: IF LESS down: 0, up: 1, diff: 0.02084 
NOTICE: End Variable down: 1, up: 1, diff: 0.02084 
NOTICE: Beginning Variable seed: 3.396, close: 3.41684, down: 1, up: 1, diff: 0.02084 
NOTICE: IF GREATER down: 1, up: 1, diff: 0.02084 
NOTICE: End Variable down: 1, up: 2, diff: 0.02084 
NOTICE: Beginning Variable seed: 3.41684, close: 3.45851, down: 1, up: 2, diff: 0.04167 
NOTICE: IF GREATER down: 1, up: 2, diff: 0.04167 
NOTICE: End Variable down: 1, up: 3, diff: 0.04167 
NOTICE: Beginning Variable seed: 3.45851, close: 3.41684, down: 1, up: 3, diff: 0.04167 
NOTICE: IF LESS down: 1, up: 3, diff: 0.04167 
NOTICE: End Variable down: 2, up: 3, diff: 0.04167 
NOTICE: Beginning Variable seed: 3.41684, close: 3.29183, down: 2, up: 3, diff: 0.12501 
NOTICE: IF LESS down: 2, up: 3, diff: 0.12501 
NOTICE: End Variable down: 3, up: 3, diff: 0.12501 
NOTICE: Beginning Variable seed: 3.29183, close: 3.29183, down: 3, up: 3, diff: 0.00000 
NOTICE: End Variable down: 3, up: 3, diff: 0.00000 
NOTICE: Beginning Variable seed: 3.29183, close: 3.54184, down: 3, up: 3, diff: 0.25001 
NOTICE: IF GREATER down: 3, up: 3, diff: 0.25001 
NOTICE: End Variable down: 3, up: 4, diff: 0.25001 
NOTICE: Beginning Variable seed: 3.54184, close: 3.83352, down: 3, up: 4, diff: 0.29168 
NOTICE: IF GREATER down: 3, up: 4, diff: 0.29168 
NOTICE: End Variable down: 3, up: 5, diff: 0.29168 
NOTICE: Beginning Variable seed: 3.83352, close: 3.89603, down: 3, up: 5, diff: 0.06251 
NOTICE: IF GREATER down: 3, up: 5, diff: 0.06251 
NOTICE: End Variable down: 3, up: 6, diff: 0.06251 
NOTICE: Beginning Variable seed: 3.89603, close: 3.83352, down: 3, up: 6, diff: 0.06251 
NOTICE: IF LESS down: 3, up: 6, diff: 0.06251 
NOTICE: End Variable down: 4, up: 6, diff: 0.06251 
NOTICE: Beginning Variable seed: 3.83352, close: 3.83352, down: 4, up: 6, diff: 0.00000 
NOTICE: End Variable down: 4, up: 6, diff: 0.00000 
NOTICE: Beginning Variable seed: 3.83352, close: 4.04187, down: 4, up: 6, diff: 0.20835 
NOTICE: IF GREATER down: 4, up: 6, diff: 0.20835 
NOTICE: End Variable down: 4, up: 7, diff: 0.20835 
NOTICE: Beginning Variable seed: 4.04187, close: 4.25021, down: 4, up: 7, diff: 0.20834 
NOTICE: IF GREATER down: 4, up: 7, diff: 0.20834 
NOTICE: End Variable down: 4, up: 8, diff: 0.20834

Successfully run. Total query runtime: 274 msec. 15 rows affected.

Проблемы возникают при попытке добавить разницу. Оператор IF был изменен с +1 на + diff:

CREATE OR REPLACE FUNCTION RSI_STATE(rsi_mat NUMERIC[], close_val numeric)
    RETURNS NUMERIC[]
LANGUAGE plpgsql
AS $$
DECLARE
    downs INTEGER;
    ups INTEGER;
    counter INTEGER;
    cl NUMERIC;
    diff NUMERIC;
BEGIN
    downs := rsi_mat[3];
    ups := rsi_mat[4];
    diff := abs(rsi_mat[2] - close_val);
    RAISE NOTICE 'Beginning Variable seed: %,  close: %,  down: %,  up: %,  diff: %', rsi_mat[2], close_val, downs, ups, diff;

    IF rsi_mat[2] > close_val then
        RAISE NOTICE 'IF LESS down: %,  up: %,  diff: %', downs, ups, diff;
        downs := rsi_mat[3] + diff;
    ELSEIF rsi_mat[2] < close_val then
        RAISE NOTICE 'IF GREATER down: %,  up: %,  diff: %', downs, ups, diff;
        ups := rsi_mat[4] + diff;
    END IF;
    cl := close_val;
    counter := rsi_mat[1] + 1;
    RAISE NOTICE 'End Variable down: %,  up: %,  diff: %', downs, ups, diff;
    RETURN ARRAY[counter,cl, downs, ups];
END;
$$;

Результаты показывают, что значения вверх и вниз не изменяются:

NOTICE:  Beginning Variable seed: <NULL>,  close: 3.37517,  down: 0,  up: 0,  diff: <NULL>
NOTICE:  End Variable down: 0,  up: 0,  diff: <NULL>
NOTICE:  Beginning Variable seed: 3.37517,  close: 3.41684,  down: 0,  up: 0,  diff: 0.04167
NOTICE:  IF GREATER down: 0,  up: 0,  diff: 0.04167
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.04167
NOTICE:  Beginning Variable seed: 3.41684,  close: 3.396,  down: 0,  up: 0,  diff: 0.02084
NOTICE:  IF LESS down: 0,  up: 0,  diff: 0.02084
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.02084
NOTICE:  Beginning Variable seed: 3.396,  close: 3.41684,  down: 0,  up: 0,  diff: 0.02084
NOTICE:  IF GREATER down: 0,  up: 0,  diff: 0.02084
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.02084
NOTICE:  Beginning Variable seed: 3.41684,  close: 3.45851,  down: 0,  up: 0,  diff: 0.04167
NOTICE:  IF GREATER down: 0,  up: 0,  diff: 0.04167
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.04167
NOTICE:  Beginning Variable seed: 3.45851,  close: 3.41684,  down: 0,  up: 0,  diff: 0.04167
NOTICE:  IF LESS down: 0,  up: 0,  diff: 0.04167
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.04167
NOTICE:  Beginning Variable seed: 3.41684,  close: 3.29183,  down: 0,  up: 0,  diff: 0.12501
NOTICE:  IF LESS down: 0,  up: 0,  diff: 0.12501
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.12501
NOTICE:  Beginning Variable seed: 3.29183,  close: 3.29183,  down: 0,  up: 0,  diff: 0.00000
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.00000
NOTICE:  Beginning Variable seed: 3.29183,  close: 3.54184,  down: 0,  up: 0,  diff: 0.25001
NOTICE:  IF GREATER down: 0,  up: 0,  diff: 0.25001
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.25001
NOTICE:  Beginning Variable seed: 3.54184,  close: 3.83352,  down: 0,  up: 0,  diff: 0.29168
NOTICE:  IF GREATER down: 0,  up: 0,  diff: 0.29168
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.29168
NOTICE:  Beginning Variable seed: 3.83352,  close: 3.89603,  down: 0,  up: 0,  diff: 0.06251
NOTICE:  IF GREATER down: 0,  up: 0,  diff: 0.06251
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.06251
NOTICE:  Beginning Variable seed: 3.89603,  close: 3.83352,  down: 0,  up: 0,  diff: 0.06251
NOTICE:  IF LESS down: 0,  up: 0,  diff: 0.06251
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.06251
NOTICE:  Beginning Variable seed: 3.83352,  close: 3.83352,  down: 0,  up: 0,  diff: 0.00000
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.00000
NOTICE:  Beginning Variable seed: 3.83352,  close: 4.04187,  down: 0,  up: 0,  diff: 0.20835
NOTICE:  IF GREATER down: 0,  up: 0,  diff: 0.20835
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.20835
NOTICE:  Beginning Variable seed: 4.04187,  close: 4.25021,  down: 0,  up: 0,  diff: 0.20834
NOTICE:  IF GREATER down: 0,  up: 0,  diff: 0.20834
NOTICE:  End Variable down: 0,  up: 0,  diff: 0.20834

Successfully run. Total query runtime: 226 msec.
15 rows affected.

Я не уверен, что проблема в логике c, синтаксисе или тупости.

1 Ответ

1 голос
/ 04 марта 2020

Ваша ошибка - определить ups и downs как integer. Таким образом, разница при округлении округляется до целого числа.

Объявите переменные как numeric, и ваша проблема будет решена.

...