SQL列的多数表决

SQL列的多数表决,sql,oracle,postgresql,Sql,Oracle,Postgresql,我需要在SQL数据库中对列进行“多数投票”。这意味着,如果有列:c0,c1,…,cn,我希望在每一行的其他列中有所提到的列中最频繁的值(以及null或随机值,否则,这并不重要)。例如,如果我们有下表: +--+--+--+------+ |c0|c1|c2|result| +--+--+--+------+ | 0| 1| 0| 0| | 0| 1| 1| 1| | 2| 2| 0| 2| | 0| 3| 1| null| 这就是我所说的对c0、c1、c2列进行多数表

我需要在SQL数据库中对列进行“多数投票”。这意味着,如果有列:
c0
c1
,…,
cn
,我希望在每一行的其他列中有所提到的列中最频繁的值(以及
null
或随机值,否则,这并不重要)。例如,如果我们有下表:

+--+--+--+------+
|c0|c1|c2|result|
+--+--+--+------+
| 0| 1| 0|     0|
| 0| 1| 1|     1|
| 2| 2| 0|     2|
| 0| 3| 1|  null|
这就是我所说的对
c0
c1
c2
列进行多数表决的意思:在第一行中,我们有两行的值
0
,一行的值
1
,因此
result=0
。在第二种情况下,我们有一个
0
,而有两个
1
,因此
result=1
,依此类推。我们假设所有列的类型都相同

如果查询简洁(可以动态构建),那就太好了。首选本机SQL,但也可以使用PL/SQL、psql


提前感谢您。

这里有一个Postgres的解决方案

SELECT t1.c0,
       t1.c1,
       t1.c2,
       (SELECT y.c
               FROM (SELECT x.c,
                            count(*) OVER (PARTITION BY x.rn) ct
                            FROM (SELECT v.c,
                                         rank() OVER (ORDER BY count(v.c) DESC) rn
                                         FROM (VALUES (t1.c0),
                                                      (t1.c1),
                                                      (t1.c2)) v(c)
                                         GROUP BY v.c) x
                            WHERE x.rn = 1) y
               WHERE y.ct = 1) result
       FROM elbat t1;

在子查询中,首先使用
rank()
获取所有具有最大计数的值。如果只有一个值具有最大计数,则使用
count()
的窗口版本进行过滤


如果需要对更多列执行此操作,只需将它们添加到
选择
值中即可

这里有一个针对博士后的解决方案

SELECT t1.c0,
       t1.c1,
       t1.c2,
       (SELECT y.c
               FROM (SELECT x.c,
                            count(*) OVER (PARTITION BY x.rn) ct
                            FROM (SELECT v.c,
                                         rank() OVER (ORDER BY count(v.c) DESC) rn
                                         FROM (VALUES (t1.c0),
                                                      (t1.c1),
                                                      (t1.c2)) v(c)
                                         GROUP BY v.c) x
                            WHERE x.rn = 1) y
               WHERE y.ct = 1) result
       FROM elbat t1;

在子查询中,首先使用
rank()
获取所有具有最大计数的值。如果只有一个值具有最大计数,则使用
count()
的窗口版本进行过滤


如果需要对更多列执行此操作,只需将它们添加到
选择
值中即可

这回答了问题的原始版本

您可以只比较这些值。对于具有两个值的示例,这两个值都不是
NULL

select t.*
       (case when ((case when c0 = 0 then 1 else -1 end) +
                   (case when c1 = 0 then 1 else -1 end) +
                   (case when c2 = 0 then 1 else -1 end)
                  ) > 0
             then 0 else 1
        end)
from t;

这回答了问题的原始版本

您可以只比较这些值。对于具有两个值的示例,这两个值都不是
NULL

select t.*
       (case when ((case when c0 = 0 then 1 else -1 end) +
                   (case when c1 = 0 then 1 else -1 end) +
                   (case when c2 = 0 then 1 else -1 end)
                  ) > 0
             then 0 else 1
        end)
from t;

这可以通过在三列中创建一个表并在该表上使用聚合函数轻松完成:

以下是博士后的工作:

select c0,c1,c2,
       (select c 
       from unnest(array[c0,c1,c2]) as t(c) 
       group by c 
       having count(*) > 1 
       order by count(*) desc 
       limit 1)
from the_table;
如果不想硬编码列名,也可以使用Postgres的JSON函数:

select t.*,
       (select t.v
        from jsonb_each_text(to_jsonb(t)) as t(c,v)
        group by t.v
        having count(*) > 1
        order by count(*) desc
        limit 1) as result
from the_table t;
请注意,上面考虑了所有列。如果要删除特定列(例如
id
列),则需要使用
to_jsonb(t)-“id”
从JSON值中删除该键

这两种解决方案都不涉及关系(两个不同的值出现的次数相同)

在线示例:


第一个解决方案可以在某种程度上“适应”Oracle,特别是如果您可以动态构建SQL:

select t.*, 
       (select c
        from (
          -- this part would need to be done dynamically
          -- if you don't know the columns
          select t.c0 as c from dual union all 
          select t.c1 from dual union all 
          select t.c2 from dual
        ) x
        group by c
        having count(*) > 1
        order by count(*) desc
        fetch first 1 rows only) as result
from the_table t;

这可以通过在三列中创建一个表并在该表上使用聚合函数轻松完成:

以下是博士后的工作:

select c0,c1,c2,
       (select c 
       from unnest(array[c0,c1,c2]) as t(c) 
       group by c 
       having count(*) > 1 
       order by count(*) desc 
       limit 1)
from the_table;
如果不想硬编码列名,也可以使用Postgres的JSON函数:

select t.*,
       (select t.v
        from jsonb_each_text(to_jsonb(t)) as t(c,v)
        group by t.v
        having count(*) > 1
        order by count(*) desc
        limit 1) as result
from the_table t;
请注意,上面考虑了所有列。如果要删除特定列(例如
id
列),则需要使用
to_jsonb(t)-“id”
从JSON值中删除该键

这两种解决方案都不涉及关系(两个不同的值出现的次数相同)

在线示例:


第一个解决方案可以在某种程度上“适应”Oracle,特别是如果您可以动态构建SQL:

select t.*, 
       (select c
        from (
          -- this part would need to be done dynamically
          -- if you don't know the columns
          select t.c0 as c from dual union all 
          select t.c1 from dual union all 
          select t.c2 from dual
        ) x
        group by c
        having count(*) > 1
        order by count(*) desc
        fetch first 1 rows only) as result
from the_table t;
在Postgres使用中,您需要主键或唯一列,
id
在示例中是唯一的:

with my_table(id, c0, c1, c2) as (
values
    (1, 0, 1, 0),
    (2, 0, 1, 1),
    (3, 2, 2, 0),
    (4, 0, 3, 1)
)

select distinct on (id) id, value
from (
    select id, value, count(*)
    from my_table t
    cross join jsonb_each_text(to_jsonb(t)- 'id')
    group by id, value
    ) s
order by id, count desc

 id | value 
----+-------
  1 | 0
  2 | 1
  3 | 2
  4 | 1
(4 rows)
无论列数多少,查询都能正常工作。

在Postgres使用中,您需要主键或唯一列,
id
在示例中是唯一的:

with my_table(id, c0, c1, c2) as (
values
    (1, 0, 1, 0),
    (2, 0, 1, 1),
    (3, 2, 2, 0),
    (4, 0, 3, 1)
)

select distinct on (id) id, value
from (
    select id, value, count(*)
    from my_table t
    cross join jsonb_each_text(to_jsonb(t)- 'id')
    group by id, value
    ) s
order by id, count desc

 id | value 
----+-------
  1 | 0
  2 | 1
  3 | 2
  4 | 1
(4 rows)


无论列数多少,查询都能正常工作。

请仅标记您正在使用的DBMS。如前所述-postgresql或oracle。我已经准备好使用所需的,尽管供应商不可知的解决方案将受到赞赏。不,当无法选择值时,
null
或默认值可以插入。只有Oracle或Oracle和Postgres?任何,我将选择一个,这是有能力的。请只标记您正在使用的DBMS。如前所述-postgresql或Oracle。我已经准备好使用所需的,尽管供应商不可知的解决方案将受到赞赏。不,当无法选择值时,可以插入
null
或默认值。只有Oracle或Oracle和Postgres?任何,我将选择一个,这是有能力的。也许我没有指出正确的-类型已知,值不存在,可以是,例如:0,2,2。也许我没有正确指出-类型是已知的,值不是,那些可能是,例如:0,2,2。我不知道值-这可能是任何东西,只有类型是已知的。我已经编辑了这个问题。@Andronicus。只能回答你提出的问题。我建议你用更合适的数据问另一个问题。也许,但最初的说法是,只有类型是已知的。我添加了一些额外的示例数据:)我不知道值-这可能是任何东西,只有类型是已知的。我已经编辑了这个问题。@Andronicus。只能回答你提出的问题。我建议你用更合适的数据问另一个问题。也许,但最初的说法是,只有类型是已知的。我添加了一些额外的示例数据:)