Ale*_*eto 25 postgresql aggregate functions greatest-n-per-group
完整问题重写
我正在寻找 First() 聚合函数。
在这里,我发现了一些几乎有效的东西:
CREATE OR REPLACE FUNCTION public.first_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
SELECT $1;
$$;
-- And then wrap an aggregate around it
CREATE AGGREGATE public.first (
sfunc = public.first_agg,
basetype = anyelement,
stype = anyelement
);
Run Code Online (Sandbox Code Playgroud)
问题是当 varchar(n) 列通过 first() 函数时,它会被转换为简单的 varchar(没有大小)。尝试在函数中将查询返回为 RETURNS SETOF anyelement,我收到以下错误:
错误:查询的结构与函数结果类型 Estado de SQL:42804 不匹配:返回的类型字符变化与第 2 列中的预期类型字符变化(40) 不匹配。上下文:PL/pgSQL 函数 vsr_table_at_time(anyelement,timestamp without time zone ) 第 31 行在 RETURN QUERY
在同一个 wiki 页面中,有一个指向该函数的C 版本的链接,该链接将替换上述内容。我不知道如何安装它,但我想知道这个版本是否可以解决我的问题。
同时,有没有办法可以更改上述函数,使其返回与输入列完全相同的类型?
Eva*_*oll 27
DISTINCT ON()顺便说一句,这正是DISTINCT ON()(不要与 混淆DISTINCT)
SELECT DISTINCT ON ( expression [, ...] )仅保留给定表达式求值为 equal 的每组行的第一行。该DISTINCT ON表达式是使用相同的规则解释ORDER BY(见上文)。请注意,每组的“第一行”是不可预测的,除非ORDER BY用于确保所需的行首先出现。例如
所以如果你要写,
SELECT myFirstAgg(z)
FROM foo
GROUP BY x,y;
Run Code Online (Sandbox Code Playgroud)
它有效
SELECT DISTINCT ON(x,y) z
FROM foo;
-- ORDER BY z;
Run Code Online (Sandbox Code Playgroud)
因为它需要第一个z. 有两个重要的区别,
您还可以选择其他列而无需进一步聚合。
SELECT DISTINCT ON(x,y) z, k, r, t, v
FROM foo;
-- ORDER BY z, k, r, t, v;
Run Code Online (Sandbox Code Playgroud)因为没有GROUP BY你不能使用(真实的)聚合。
CREATE TABLE foo AS
SELECT * FROM ( VALUES
(1,2,3),
(1,2,4),
(1,2,5)
) AS t(x,y,z);
SELECT DISTINCT ON (x,y) z, sum(z)
FROM foo;
-- fails, as you should expect.
SELECT DISTINCT ON (x,y) z, sum(z)
FROM foo;
-- would not otherwise fail.
SELECT myFirstAgg(z), sum(z)
FROM foo
GROUP BY x,y;
Run Code Online (Sandbox Code Playgroud)ORDER BY另外,虽然我没有加粗,但我现在会
请注意,每个集合的“第一行”是不可预测的,除非使用 ORDER BY 来确保所需的行首先出现。例如
总是使用ORDER BYwithDISTINCT ON
我想很多人都在寻找first_value, Ordered-Set Aggregate Functions。只是想把它扔出去。如果函数存在,它看起来像这样:
SELECT a, b, first_value() WITHIN GROUP (ORDER BY z)
FROM foo
GROUP BY a,b;
Run Code Online (Sandbox Code Playgroud)
但是,唉,你可以做到这一点。
SELECT a, b, percentile_disc(0) WITHIN GROUP (ORDER BY z)
FROM foo
GROUP BY a,b;
Run Code Online (Sandbox Code Playgroud)
不是您问题的直接答案,但您应该尝试first_value窗口函数。它是这样工作的:
CREATE TABLE test (
id SERIAL NOT NULL PRIMARY KEY,
cat TEXT,
value VARCHAR(2)
date TIMESTAMP WITH TIME ZONE
Run Code Online (Sandbox Code Playgroud)
);
然后,如果您想要每个cat(类别)中的第一项,您将这样查询:
SELECT
cat,
first_value(date) OVER (PARTITION BY cat ORDER BY date)
FROM
test;
Run Code Online (Sandbox Code Playgroud)
或者:
SELECT
cat,
first_value(date) OVER w
FROM
test
WINDOW w AS (PARTITION BY cat ORDER BY date);
Run Code Online (Sandbox Code Playgroud)
小智 6
是的,我通过使用 PostgreSQL 9.4+ 中的一些功能找到了一个简单的方法来处理你的案例
让我们看看这个例子:
select (array_agg(val ORDER BY i))[1] as first_value_orderby_i,
(array_agg(val ORDER BY i DESC))[1] as last_value_orderby_i,
(array_agg(val))[1] as last_value_all,
(array_agg(val))[array_length(array_agg(val),1)] as last_value_all
FROM (
SELECT i, random() as val
FROM generate_series(1,100) s(i)
ORDER BY random()
) tmp_tbl
Run Code Online (Sandbox Code Playgroud)
我希望它对你的情况有所帮助。
| 归档时间: |
|
| 查看次数: |
32654 次 |
| 最近记录: |