Postgresql – Select distinct multiple columns with one result column

postgresql

I have a table like the following:

CREATE TABLE aschema.atable
 (
  id       BIGSERIAL,
  col_a    aschema.anenum,
  col_b    aschema.anenum,
  col_c    aschema.anenum
)

and I would like to do something like

SELECT DISTINCT unnest(array_agg(col_a, col_b, col_c)) as anenum_value
  FROM aschema.atable
  WHERE anenum_value IS NOT NULL

but I do not know if it makes sense.
Maybe with an index over each of the three column I can simply select independently the three columns like that:

SELECT DISTINCT value FROM (
SELECT col_a as value
  FROM aschema.atable  WHERE col_a IS NOT NULL
UNION
SELECT col_b as value
  FROM aschema.atable  WHERE col_b IS NOT NULL
UNION
SELECT col_c as value
  FROM aschema.atable  WHERE col_c IS NOT NULL
)

But I am not sure about the performance.

Actually I have rows like

id  col_a  col_b  col_c
1   ABD    CDE    XYZ
2   CDE    null   null
3   ABD    null   null
3   FGH    LMN   null

And I expect as a result

ABC
ABD
CDE
FGH
LMN
XYZ

Any recommendation and good example?

Best Answer

There another several solutions:

  1. Using lateral join and values:

    select distinct
      x
    from
      aschema.atable cross join lateral
        (values(col_a),(col_b),(col_c)) as t(x)
    where
      x is not null
    order by
      x;
    
  2. Using arrays:

    select distinct
      x
    from
      (select unnest(array[col_a,col_b,col_c]) from aschema.atable) as     t(x)
    where
      x is not null
    order by
      x;
    
  3. Normalize data structure:

    CREATE TABLE aschema.atable
    (
      id         bigserial,      -- Just an ID
      trinity_id bigint not null -- It is ID from your original table
      what       int check(what in (1,2,3)), -- 1 - a, 2 - b, 3 - c 
      value      aschema.anenum,
      unique (trinity_id,what),  
      unique (trinity_id,value)  -- To be sure that each trinity have distinct values
    );
    

And for now your data could be:

id  trinity_id what value
1   1          1    ABD
2   1          2    CDE
3   1          3    XYZ
4   2          1    CDE
5   3          1    ABD
6   4          1    FGH
7   4          2    LMN