SQL列的多数表决
我需要在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列进行多数表
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。只能回答你提出的问题。我建议你用更合适的数据问另一个问题。也许,但最初的说法是,只有类型是已知的。我添加了一些额外的示例数据:)