Oracle how to get most common value in a column for multiple columns? Oracle how to get most common value in a column for multiple columns? oracle oracle

Oracle how to get most common value in a column for multiple columns?


Here is one way, using analytic functions and keep:

select id,       min(col1) keep(dense_rank first order by cnt_col1 desc) as col1_mode,       min(col2) keep(dense_rank first order by cnt_col2 desc) as col2_mode,       min(col3) keep(dense_rank first order by cnt_col3 desc) as col3_modefrom (select id,             count(*) over (partition by id, col1) as cnt_col1,             count(*) over (partition by id, col2) as cnt_col2,             count(*) over (partition by id, col3) as cnt_col3      from t     ) tgroup by id;

The most frequent value is called the "mode" in statistics, and Oracle offers a function to calculate this. So, an easier way is to use stats_mode():

   select id,         stats_mode(col1) as mode_col1,         stats_mode(col2) as mode_col2,         stats_mode(col3) as mode_col3  from table t  group by id;

EDIT:

As noted in a comment, stats_mode() does not count NULL values. The easiest way to fix this is to find some value that is not in the data and do:

   select id,          stats_mode(coalesce(col1, '<null>')) as mode_col1,          stats_mode(coalesce(col2, '<null>')) as mode_col2,          stats_mode(coalesce(col3, '<null>')) as mode_col3  from table t  group by id;

The other way is to revert to the first approach or something similar:

select id,       (case when sum(case when col1 = mode_col1 then 1 else 0 end) >= sum(case when col1 is null then 1 else 0 end)             then mode_col1             else NULL        end) as mode_col1,       (case when sum(case when col2 = mode_col2 then 1 else 0 end) >= sum(case when col2 is null then 1 else 0 end)             then mode_col2             else NULL        end) as mode_col2,       (case when sum(case when col3 = mode_col13 then 1 else 0 end) >= sum(case when col3 is null then 1 else 0 end)             then mode_col3             else NULL        end) as mode_col3from (select t.*,             stats_mode(col1) over (partition by id) as mode_col1,             stats_mode(col2) over (partition by id) as mode_col2,             stats_mode(col3) over (partition by id) as mode_col3      from table t     ) tgroup by id;