sql >> Databáze >  >> RDS >> PostgreSQL

Postgres agregační funkce pro výpočet vektorového průměru rychlosti větru (vektorová velikost) a směru větru (vektorový směr)

Nejprve se omlouvám, pokud zde poruším pravidla pro zveřejňování, první plakát a tak dále.

Chtěl jsem použít výše uvedenou odpověď spolu s přídavkem timescaledb do postgres pro mou meteorologickou stanici pro kutily, ale ukázalo se, že funkce není paralelně bezpečná. Také afik použití atan nepřináší správnou odpověď.

Takže toto je moje upravená verze, která by podle mě měla být paralelně bezpečná a místo toho používá atan2.

DROP AGGREGATE IF EXISTS vector_avg(float, float) CASCADE;
DROP TYPE IF EXISTS vector_sum CASCADE;
DROP TYPE IF EXISTS avg_vector CASCADE;

CREATE TYPE vector_sum AS (x float, y float, count int);
CREATE TYPE avg_vector AS (magnitude float, direction float);

CREATE OR REPLACE FUNCTION sum_vector (vectors vector_sum, magnitude float, direction float)
  RETURNS vector_sum LANGUAGE sql PARALLEL SAFE STRICT AS
'SELECT vectors.x + (magnitude * cos(radians(direction))), vectors.y + (magnitude * sin(radians(direction))), vectors.count + 1';

CREATE OR REPLACE FUNCTION combine_sum (part1 vector_sum , part2 vector_sum)
  RETURNS vector_sum LANGUAGE sql PARALLEL SAFE STRICT AS
'SELECT (part1.x+part2.x)/2,(part1.y+part2.y)/2,part1.count+part2.count';

CREATE OR REPLACE FUNCTION avg_vector_finalfunc(vectors vector_sum)
RETURNS avg_vector
AS
$$
DECLARE
        x float;
        y float;
        d float;
BEGIN
    BEGIN
        IF vectors.count = 0 THEN
            RETURN (NULL, NULL)::avg_vector;
        END IF;

        x := (vectors.x/vectors.count);
        y := (vectors.y/vectors.count);

        -- This means the vector is null vector
        -- Please see: https://math.stackexchange.com/a/3682/10842
        IF x = 0 OR y = 0 THEN
            RETURN (0, 0)::avg_vector;
        END IF;

         d:=degrees(atan2(y,x));

        -- atan2 returns negative result for angles > 180

        IF d < 0 THEN
          d := d+360;
        END IF;

        RETURN (sqrt(power(x, 2) + power(y, 2)), d )::avg_vector;
    EXCEPTION WHEN others THEN
        RETURN (NULL, NULL)::avg_vector;
    END;
END;
$$
LANGUAGE 'plpgsql'
PARALLEL SAFE
RETURNS NULL ON NULL INPUT;

CREATE AGGREGATE vector_avg (float, float) (
   sfunc     = sum_vector
 , stype     = vector_sum
 , combinefunc = combine_sum
 , finalfunc = avg_vector_finalfunc
 , initcond  = '(0.0, 0.0, 0)'
 , PARALLEL  = SAFE

Test z velmi malého vzorku:

psql -d weather -c "select * from windavgtest;"
             time              | direction | speed 
-------------------------------+-----------+-------
 2019-08-01 16:51:53.199357+00 |       170 |     1
 2019-08-01 16:51:54.388392+00 |       170 |     1
 2019-08-01 16:51:55.335034+00 |       170 |     1
 2019-08-01 16:51:56.362812+00 |       170 |     1
 2019-08-01 16:52:07.191919+00 |       190 |     1
 2019-08-01 16:52:08.250756+00 |       190 |     1
 2019-08-01 16:52:09.193265+00 |       190 |     1
 2019-08-01 16:52:10.224283+00 |       190 |     1
(8 rows)

výnosy:

psql -d weather -c  "select round((vector_avg(speed, direction)).direction) AS wdirection from windavgtest;
"
 wdirection 
------------
        180
(1 row)


  1. Jak zkontrolovat, které zámky drží na stole

  2. Jak vybrat a seřadit podle sloupců, které nejsou v SQL příkazu Groupy By - Oracle

  3. Při kontrole připojení se nelze připojit k žádnému ze zadaných hostitelů MySQL

  4. jak získat seznam názvů schémat databází MySql pomocí java JDBC