【发布时间】:2015-07-06 09:54:36
【问题描述】:
我正在定义时变整数,即时变整数段的数组,后者是与时间戳范围相关联的整数值。
CREATE TYPE integerTS AS (val integer, p tsrange);
CREATE TYPE integerTT AS (traj integerTS[]);
这种值的一个例子是
select integerTT(ARRAY[
integerTS(1, '2012-01-01 08:00:00', '2012-01-01 08:10:00'),
integerTS(2, '2012-01-01 08:10:00', '2012-01-01 08:20:00')
])
我可以定义 min、max 和 sum 聚合函数,但在这些类型上,例如
WITH Values AS (
SELECT integerTT(ARRAY[
integerTS(3, '2012-01-01 08:00:00', '2012-01-01 08:20:00')]) as val
UNION
SELECT integerTT(ARRAY[
integerTS(2, '2012-01-01 08:10:00', '2012-01-01 08:30:00')])
UNION
SELECT integerTT(ARRAY[
integerTS(1, '2012-01-01 08:20:00', '2012-01-01 08:40:00')])
)
SELECT min(val)
from Values
结果
integerTT(ARRAY[
integerTS(3, '2012-01-01 08:00:00', '2012-01-01 08:10:00'),
integerTS(2, '2012-01-01 08:10:00', '2012-01-01 08:20:00'),
integerTS(1, '2012-01-01 08:20:00', '2012-01-01 08:40:00')])
但是,我无法为时变整数定义计数聚合函数。 我开始定义函数如下。
CREATE OR REPLACE FUNCTION count(tt1 integerTT, tt2 integerTT) RETURNS integerTT AS
$BODY$
DECLARE
BEGIN
-- 0 is a dummy value
return integerTT(count(integerTS(0,getT(tt1)), integerTS(0,getT(tt2))));
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION count(ts1 integerTS, ts2 integerTS) RETURNS integerTS[] AS
$BODY$
DECLARE
intersection tsrange;
result integerTS[];
BEGIN
intersection := getT(ts1) * getT(ts2);
IF isempty(intersection) THEN
IF getT(ts1) << getT(ts2) THEN
result := ARRAY[integerTS(1,getT(ts1)),integerTS(1,getT(ts2))];
ELSE
result := ARRAY[integerTS(1,getT(ts2)),integerTS(1,getT(ts1))];
END IF;
ELSE
IF lower(getT(ts1)) < lower(intersection) THEN
result := array_append(result,integerTS(1,tsrange(lower(getT(ts1)), lower(intersection))));
END IF;
IF lower(getT(ts2)) < lower(intersection) THEN
result := array_append(result,integerTS(1,tsrange(lower(getT(ts2)), lower(intersection))));
END IF;
result := array_append(result,integerTS(2,intersection));
IF upper(intersection) < upper(getT(ts1)) THEN
result := array_append(result,integerTS(1,tsrange(upper(intersection), upper(getT(ts1)))));
END IF;
IF upper(intersection) < upper(getT(ts2)) THEN
result := array_append(result,integerTS(1,tsrange(upper(intersection), upper(getT(ts2)))));
END IF;
END IF;
RETURN result;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;
然后
WITH Values AS (
SELECT integerTT(ARRAY[
integerTS(3, '2012-01-01 08:00:00', '2012-01-01 08:20:00')]) as val
UNION
SELECT integerTT(ARRAY[
integerTS(2, '2012-01-01 08:10:00', '2012-01-01 08:30:00')])
UNION
SELECT integerTT(ARRAY[
integerTS(1, '2012-01-01 08:20:00', '2012-01-01 08:40:00')])
)
SELECT count(val)
from Values
得到正确的值如下
integerTT(ARRAY[
integerTS(1, '2012-01-01 08:00:00', '2012-01-01 08:10:00'),
integerTS(2, '2012-01-01 08:10:00', '2012-01-01 08:30:00'),
integerTS(1, '2012-01-01 08:30:00', '2012-01-01 08:40:00')])
但是,当聚合函数定义如下
CREATE AGGREGATE count (integerTT)
(
sfunc = count,
stype = integerTT
);
不起作用,因为它总是返回 1 和 2 个计数值。例如
WITH Values AS (
SELECT integerTT(ARRAY[
integerTS(3, '2012-01-01 08:00:00', '2012-01-01 08:20:00')]) as val
UNION
SELECT integerTT(ARRAY[
integerTS(4, '2012-01-01 08:00:00', '2012-01-01 08:20:00')]) as val
UNION
SELECT integerTT(ARRAY[
integerTS(5, '2012-01-01 08:00:00', '2012-01-01 08:20:00')]) as val
UNION
SELECT integerTT(ARRAY[
integerTS(6, '2012-01-01 08:00:00', '2012-01-01 08:20:00')]) as val
UNION
SELECT integerTT(ARRAY[
integerTS(7, '2012-01-01 08:00:00', '2012-01-01 08:20:00')]) as val
)
SELECT count(val)
from Values
返回
integerTT(ARRAY[
integerTS(2, '2012-01-01 08:00:00', '2012-01-01 08:20:00')])
虽然它应该返回
integerTT(ARRAY[
integerTS(5, '2012-01-01 08:00:00', '2012-01-01 08:20:00')])
如何定义时变计数?我使用的是 PostgreSQL 版本 9.4.1。
【问题讨论】:
标签: postgresql count aggregate-functions user-defined