我有一个包含很多列的表格,我想运行一个查询来查找每列中最常见的值。
通常对于一个列,我会运行类似:
SELECT country
FROM users
GROUP BY country
ORDER BY count(*) DESC
LIMIT 1
PostgreSQL是否有内置函数来执行此操作,或者任何人都可以建议我可以运行的查询来实现此目的吗?
答案 0 :(得分:3)
使用相同的查询,您应该执行多个列:
SELECT *
FROM
(
SELECT country
FROM users
GROUP BY 1
ORDER BY count(*) DESC
LIMIT 1
) country
,(
SELECT city
FROM users
GROUP BY 1
ORDER BY count(*) DESC
LIMIT 1
) city
这适用于任何类型,并将返回同一行中的所有值,并且列具有其原始名称。
对于更多列,只有更多的subquerys:
,(
SELECT someOtherColumn
FROM users
GROUP BY 1
ORDER BY count(*) DESC
LIMIT 1
) someOtherColumn
修改:
您也可以通过窗口功能与它联系。然而,它在性能和可读性方面都不会更好。
答案 1 :(得分:1)
如果我这样做,我会写一个像这样的查询:
SELECT 'country', country
FROM users
GROUP BY country
ORDER BY count(*) DESC
LIMIT 1
UNION ALL
SELECT 'city', city
FROM USERS
GROUP BY city
ORDER BY count(*) DESC
LIMIT 1
-- etc.
应该注意,这只适用于所有列都是兼容类型的情况。如果不是,您可能需要一个不同的解决方案。
答案 2 :(得分:1)
此窗口函数版本将分别读取users表和计算表。相关子查询版本将为每个列读取一次users表。如果在OPs情况下列很多,那么我的猜测是这更快。 SQL Fiddle
select distinct on (country_count, age_count) *
from (
select
country,
count(*) over(partition by country) as country_count,
age,
count(*) over(partition by age) as age_count
from users
) s
order by country_count desc, age_count desc
limit 1
答案 3 :(得分:1)
从PG 9.4开始,有以下聚合函数:
mode() WITHIN GROUP (ORDER BY sort_expression)
返回最常见的输入值(如果有多个同等频率的结果,则任意选择第一个)
对于早期版本,您可以创建一个......
CREATE OR REPLACE FUNCTION mode_array(anyarray)
RETURNS anyelement AS
$BODY$
SELECT a FROM unnest($1) a GROUP BY 1 ORDER BY COUNT(1) DESC, 1 LIMIT 1;
$BODY$
LANGUAGE SQL IMMUTABLE;
CREATE AGGREGATE mode(anyelement)(
SFUNC = array_append, --Function to call for each row. Just builds the array
STYPE = anyarray,
FINALFUNC = mode_array, --Function to call after everything has been added to array
INITCOND = '{}'--Initialize an empty array when starting
) ;
用法:SELECT mode(column) FROM table;