我正在使用SQL查询
SELECT round(avg(int_value)) AS modal_value FROM t;
获得modal value,这是不正确的,但是第一个显示某些结果的选项。
所以,我的问题是,“如何做正确的事情?”。
使用PostgreSQL 8.3+,我们可以使用this user-defined agregate 来定义模式:
CREATE FUNCTION _final_mode(anyarray) RETURNS anyelement AS $f$
SELECT a FROM unnest($1) a
GROUP BY 1 ORDER BY COUNT(1) DESC, 1
LIMIT 1;
$f$ LANGUAGE 'sql' IMMUTABLE;
CREATE AGGREGATE mode(anyelement) (
SFUNC=array_append, STYPE=anyarray,
FINALFUNC=_final_mode, INITCOND='{}'
);
但是,作为用户定义的平均值,对于大表,它可能很慢(比较sum / count与buildin AVG函数)。 对于PostgreSQL 9+,没有用于计算统计模式值的直接(buildin)函数?也许使用pg_stats
... 如何做< / strong>类似
SELECT (most_common_vals(int_value))[1] AS modal_value FROM t;
pg_stats VIEW可用于此类任务(甚至一次,手动)?
答案 0 :(得分:4)
由于PostgreSQL 9.4有一个内置的聚合函数mode
。它像
SELECT mode() WITHIN GROUP (ORDER BY some_value) AS modal_value FROM tbl;
在此处阅读有关有序集合函数的更多信息:
36.10.3. Ordered-Set Aggregates
Built-in Ordered-Set Aggregate Functions
查看有关处理旧版Postgres的其他答案。
答案 1 :(得分:1)
您可以尝试以下内容:
SELECT int_value, count(*)
FROM t
GROUP BY int_value
ORDER BY count(*) DESC
LIMIT 1;
背后的想法 - 你得到每个int_value
的计数,然后对它们进行排序(以便最大的count
先行),然后LIMIT
查询到第一行,仅获得最高计数的int_value
。
答案 2 :(得分:1)
如果您想按小组进行操作:
select
int_value * 10 / (select max(int_value) from t) g,
min(int_value) "from",
max(int_value) "to",
count(*) total
from t
group by 1
order by 4 desc
答案 3 :(得分:0)
在问题介绍中,我引用了this link一个很好的SQL编码解决方案(@IgorRomanchenko在这个答案中使用了相同的算法)。 @ClodoaldoNeto显示了一个“新解决方案”,但是我评论的是scalars and measures,而不是当前问题的答案。
粘贴了2个月和~40个视图,没有新问题 ...
仅使用此页面和引用链接的信息(以及缺乏进一步信息的证据)的结论。总结:
用户定义的聚合mode()
就足够了,我们不需要内置(编译)版本。
没有优化的基础设施,内置的功能比用户定义的要好。
我在
等语境中测试了cited SQL aggregate functionSELECT mode(some_value) AS modal_value FROM t;
而且,在我的测试中,它很快......所以,不能证明“内置函数”(如Oracle的STATS_MODE
),只能在“统计包”需求上下文中 - 但如果你会花时间和记忆来安装我建议R
language的东西。
另一个隐含的问题是关于一个统计软件包“准备”或使用一些PostgreSQL基础设施(如pg_stats)... @IgorRomanchenko评论的“规范答案”的一个很好的线索:“pg_stat
(...)仅包含估算值,而不包含确切的值”。因此,模式功能无法像我想象的那样利用基础设施。
注意:我们必须记住,对于“模态间隔”,我们可以使用另一个函数,请参阅@ ClodoaldoNeto的答案。
答案 4 :(得分:0)
模式是最有价值的,所以我sobreescrevi我发现here的功能,我做了这个:
CREATE OR REPLACE FUNCTION _final_mode(anyarray)
RETURNS anyelement AS
$BODY$
SELECT
CASE
WHEN t1.cnt <> t2.cnt THEN t1.a
ELSE NULL
END
FROM
(SELECT a, COUNT(*) AS cnt
FROM unnest($1) a
WHERE a IS NOT NULL
GROUP BY 1
ORDER BY COUNT(*) DESC, 1
LIMIT 1
) as t1,
(SELECT a,
COUNT(*) AS cnt
FROM unnest($1) a
WHERE a IS NOT NULL
GROUP BY 1
ORDER BY COUNT(*) DESC, 1
LIMIT 2 OFFSET 1
) as t2
$BODY$
LANGUAGE 'sql' IMMUTABLE;
-- Tell Postgres how to use our aggregate
CREATE AGGREGATE mode(anyelement) (
SFUNC=array_append, --Function to call for each row. Just builds the array
STYPE=anyarray,
FINALFUNC=_final_mode, --Function to call after everything has been added to array
INITCOND='{}' --Initialize an empty array when starting
);