Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 使用多列在postgres中自定义聚合 免责声明:解决方案如下_Sql_Postgresql - Fatal编程技术网

Sql 使用多列在postgres中自定义聚合 免责声明:解决方案如下

Sql 使用多列在postgres中自定义聚合 免责声明:解决方案如下,sql,postgresql,Sql,Postgresql,我有一组查询中的记录,列为(idx、时间、类别、重量、距离): idx是一个描述某种关系的整数值 time是不带时区的时间戳,可以(几乎)取任意值,但每个值都会出现多次(对于每个idx和类别) category是VARCHAR和一个分类变量;它的价值是有限的,而且会经常出现 重量为双精度 距离是一些预先计算的值 这些行可以如下所示: (1, '2017-01-01 00:00', 'class_a', 1, 234.5) (1, '2017-01-01 00:00', 'class_a',

我有一组查询中的记录,列为
(idx、时间、类别、重量、距离)

  • idx
    是一个描述某种关系的
    整数
  • time
    是不带时区的
    时间戳
    ,可以(几乎)取任意值,但每个值都会出现多次(对于每个
    idx
    类别
  • category
    VARCHAR
    和一个分类变量;它的价值是有限的,而且会经常出现
  • 重量
    双精度
  • 距离
    是一些预先计算的值
这些行可以如下所示:

(1, '2017-01-01 00:00', 'class_a', 1, 234.5)
(1, '2017-01-01 00:00', 'class_a', 1, 987.1)
(1, '2017-01-01 00:00', 'class_a', 1, 1.23)
(1, '2017-01-01 00:00', 'class_b', 1, 48.5)
(2, '2017-01-01 00:00', 'class_a', 1, 8763.5)
(1, '2017-01-01 00:13', 'class_a', 1, 598.02)
(1, '2017-01-01 00:13', 'class_b', 1, 76.9)
...
(2, '2017-01-27 21:07', 'class_b', 1, 184.0)
问题是什么? 我正在寻找一种解决方案来计算此类数据的自定义聚合,但我几乎找不到任何关于如何实际执行此操作的说明或示例(希望在不向postgres编写C扩展的情况下实现)

我觉得设置一个自定义聚合(此处命名为
加权密度
)应该是实现类似于概述的查询的正确方法。我的目标是最终得到一个结果集,其中化合物
(idx,time,category)
是唯一的,其
wd
是使用相关行中的所有
权重和
距离值来计算的

免责声明:解决方案如下 到目前为止我试过什么? 首先,我从数据库中获取整行数据,并使用另一种程序和语言(python)离线计算聚合。但这相当耗费资源,应该在数据库服务器上运行,而不是在本地计算机上运行(也是为了确保完整性)

然后,我尝试设置一个postgres函数,用一行计算结果值:

CREATE OR REPLACE FUNCTION _gaussian_density(
    IN DOUBLE PRECISION, -- the weight
    IN DOUBLE PRECISION, -- the distance
    IN DOUBLE PRECISION  -- the maximum distance
  ) RETURNS DOUBLE PRECISION AS
$BODY$
BEGIN
  -- calculate weighted density, using max distance;
  -- this calculation itself doesn't really matter; it's some sort
  -- of density using a cropped gaussian kernel, for those who ask.
  RETURN
    CASE
      WHEN ABS($2) > ABS($3) THEN 0.0
      WHEN ABS($2) <= 0.0 THEN 1.0
      ELSE
        $1 * (
          1.0 / |/ (2.0 * PI())
        ) * POWER(EXP(-1 * (3.0 * ABS($2) / ABS($3))), 2)
        / 0.4
    END;
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 10;
但这正是我被卡住的地方,我只是不能正确地理解它,似乎我需要一个例子或一点提示,将我推向正确的方向,说明如何正确地创建和使用自定义聚合

为你们干杯,提前感谢你们

解决方案 感谢@klin指出我错过了携带聚合状态。现在,这终于起作用了:

CREATE FUNCTION _gaussian_density(
    weight FLOAT8,
    distance FLOAT8,
    maxdist FLOAT8
  )
RETURNS FLOAT8
IMMUTABLE
CALLED ON NULL INPUT
LANGUAGE plpgsql
AS $$
  DECLARE
    abs_weight FLOAT8;
    abs_distance FLOAT8;
    abs_maxdist FLOAT8;
    dist_weight FLOAT8;
  BEGIN
    -- calculate weighted density, using max distance;
    -- this calculation itself doesn't really matter; it's some sort
    -- of density using a cropped gaussian kernel, for the curious
    abs_weight := ABS(COALESCE(weight, 1.0));
    abs_distance := ABS(COALESCE(distance, 0.0));
    abs_maxdist := ABS(COALESCE(maxdist, 0.0));
    IF abs_distance > abs_maxdist THEN RETURN 0.0; END IF;
    IF abs_distance <= 0.0 THEN RETURN 1.0 * abs_weight; END IF;
    RETURN abs_weight * (
            1.0 / |/ (2.0 * PI())
          ) * POWER(EXP(-1 * (3.0 * abs_distance / abs_maxdist)), 2)
          / 0.4;
  END;
$$;

CREATE FUNCTION _gaussian_statetransition(
    agg_state FLOAT8, -- carry the state!
    weight FLOAT8,
    distance FLOAT8,
    maxdist FLOAT8)
RETURNS FLOAT8
IMMUTABLE
LANGUAGE plpgsql
AS $$
  BEGIN
    RETURN
      agg_state + _gaussian_density(weight, distance, maxdist);
  END;
$$;

CREATE AGGREGATE weighted_density(FLOAT8, FLOAT8, FLOAT8)
(
    sfunc = _gaussian_statetransition,
    stype = FLOAT8,
    initcond = 0
);
创建函数\u高斯\u密度(
重量浮动8,
距离浮动8,
maxdist浮点8
)
返回浮动8
不变的
调用空输入
语言plpgsql
作为$$
声明
abs_重量浮子8;
abs_距离8;
abs_maxdist FLOAT8;
距离重量浮动8;
开始
--使用最大距离计算加权密度;
--这个计算本身并不重要;这是某种
--使用剪切高斯核计算密度,出于好奇
abs_重量:=abs(聚结(重量,1.0));
abs_距离:=abs(聚合(距离,0.0));
abs_maxdist:=abs(聚合(maxdist,0.0));
如果abs_distance>abs_maxdist,则返回0.0;如果结束;

如果abs_distance函数
\u gaussian_density()
应取决于上一步中计算的值。如果在您的情况下,这是第一个参数
weight
,则初始条件不应为0,因为接下来的所有计算结果都将为零。我假设
weight
的初始值为1.0:

DROP AGGREGATE weighted_density(DOUBLE PRECISION, DOUBLE PRECISION);
CREATE AGGREGATE weighted_density(DOUBLE PRECISION, DOUBLE PRECISION)
(
    sfunc = _gaussian_density,
    stype = DOUBLE PRECISION,
    initcond = 1.0 -- !!
);
请注意,聚合不使用表中的列
weight
,因为它是内部状态值,仅应声明初始条件,并作为最终结果返回

SELECT
    idx, time, category,
    weighted_density(distance, 10000) AS wd -- !!
FROM my_table
GROUP BY idx, time, category  
ORDER BY idx, time, category;

 idx |        time         | category |         wd          
-----+---------------------+----------+---------------------
   1 | 2017-01-01 00:00:00 | class_a  |   0.476331421206002
   1 | 2017-01-01 00:00:00 | class_b  |   0.968750868953701
   1 | 2017-01-01 00:13:00 | class_a  |    0.69665860026144
   1 | 2017-01-01 00:13:00 | class_b  |   0.952383202706387
   2 | 2017-01-01 00:00:00 | class_a  | 0.00519142111518706
   2 | 2017-01-27 21:07:00 | class_b  |   0.893107967346503
(6 rows)    

我不确定我是否正确理解了你的意图,但是我的话应该会让你走上正确的道路。

哦,谢谢你指出国家需要继续下去。我现在让它工作了;将用我提出的解决方案更新我的问题。非常感谢,伙计!
DROP AGGREGATE weighted_density(DOUBLE PRECISION, DOUBLE PRECISION);
CREATE AGGREGATE weighted_density(DOUBLE PRECISION, DOUBLE PRECISION)
(
    sfunc = _gaussian_density,
    stype = DOUBLE PRECISION,
    initcond = 1.0 -- !!
);
SELECT
    idx, time, category,
    weighted_density(distance, 10000) AS wd -- !!
FROM my_table
GROUP BY idx, time, category  
ORDER BY idx, time, category;

 idx |        time         | category |         wd          
-----+---------------------+----------+---------------------
   1 | 2017-01-01 00:00:00 | class_a  |   0.476331421206002
   1 | 2017-01-01 00:00:00 | class_b  |   0.968750868953701
   1 | 2017-01-01 00:13:00 | class_a  |    0.69665860026144
   1 | 2017-01-01 00:13:00 | class_b  |   0.952383202706387
   2 | 2017-01-01 00:00:00 | class_a  | 0.00519142111518706
   2 | 2017-01-27 21:07:00 | class_b  |   0.893107967346503
(6 rows)