SQL用于查找多列的多数值

时间:2015-07-24 14:11:35

标签: sql postgresql

我有一张这样的表:

 id  | value1 | value2 | value3
-----+--------+--------+--------
 id1 | a      | a      | b
 id2 | a      | b      | c
 id3 | b      | b      | c
 id4 | c      | c      | c

我想找到大多数值匹配的行(即至少有两个值匹配),因此对于上面给出的数据,输出I' d像:

 id  | majority_value
-----+----------------
 id1 | a
 id3 | b
 id4 | c

3 个答案:

答案 0 :(得分:3)

所有值列的日期类型必须匹配(或将所有值转换为相同类型)。

简单案例

对于正好3列值的简单情况,这应该是最快的,所有这些 NOT NULL id列不必是唯一的。

SELECT id, CASE value1 WHEN value2 THEN value2 ELSE value3 END AS val
FROM   tbl
WHERE  value1 = value2 OR value2 = value3 OR value1 = value3
ORDER  BY 1;

对NULL值不起作用。 (可以很容易地扩展。)

一般解决方案

对于任意奇数个值列(为偶数定义一个决胜局!)。 id列必须是唯一的。

SELECT t.id, t1.val
FROM   tbl t
     , LATERAL (VALUES (value1), (value2), (value3)) t1(val) -- list all
GROUP  BY 1, 2
HAVING count(*) > 1  -- 1 being 3/2 (integer division)
ORDER  BY 1;

SQL Fiddle(使用NULL值扩展的测试用例)。

甚至适用于NULL值。

类似于your@Giorgos'提示,但VALUES表达式效率更高。这个相关答案的细节:

答案 1 :(得分:1)

您可以尝试这种替代方案,看看它与您的解决方案的比较:

SELECT id, t.x
FROM value_table
JOIN LATERAL (
   SELECT value1 AS x UNION ALL 
   SELECT value2 UNION ALL 
   SELECT value3) t ON true
GROUP BY id, t.x
HAVING COUNT(*) > 1

Demo here

答案 2 :(得分:0)

这是一个可行的解决方案,它将不同的值组合到一个数组中,然后取消它们并计算出每个id的计数。这是查询:

SELECT id, value AS majority_value FROM (
SELECT id, unnest(values) AS value, count(1) FROM (
    select *, array[value1, value2, value3] AS values from value_table
    ) a GROUP BY id, value
) b WHERE count > 1;

这是它的EXPLAIN ANALYZE输出:

                                                           QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=2509.60..2559.60 rows=20000 width=64) (actual time=0.079..0.082 rows=3 loops=1)
   Sort Key: b.id
   Sort Method: quicksort  Memory: 25kB
   ->  Subquery Scan on b  (cost=778.83..1080.83 rows=20000 width=64) (actual time=0.058..0.067 rows=3 loops=1)
         ->  HashAggregate  (cost=778.83..880.83 rows=20000 width=128) (actual time=0.056..0.059 rows=3 loops=1)
               Filter: (count(1) > 1)
               Rows Removed by Filter: 5
               ->  Seq Scan on value_table  (cost=0.00..268.83 rows=51000 width=128) (actual time=0.014..0.032 rows=12 loops=1)
 Total runtime: 0.127 ms
(9 rows)

我希望存在更有效的查询。