Получить отличительные значения без нуля - PullRequest
0 голосов
/ 30 апреля 2020

У меня есть такая таблица;

--Table_Name--
A   |  B    | C
-----------------
A1    NULL    NULL   
A1    NULL    NULL    
A2    NULL    NULL    
NULL  B1      NULL    
NULL  B2      NULL    
NULL  B3      NULL    
NULL  NULL    C1 

Я хочу получить вот так;

--Table_Name--
A   |  B    | C
-----------------
A1    B1      C1    
A2    B2      NULL    
NULL  B3      NULL

Как мне это сделать?

Ответы [ 2 ]

2 голосов
/ 30 апреля 2020

Вот один из вариантов:

  • выборочные данные взяты из строки # 1 - 9
  • следующие CTE (строки # 11-13) выбирают ранжированные отличные ненулевые значения из каждого столбца
  • последний запрос (строка № 15 и далее) возвращает желаемый результат путем внешнего объединения предыдущих CTE по ранжированному значению

SQL> with test (a, b, c) as
  2  (select 'A1', null, null from dual union all
  3   select 'A1', null, null from dual union all
  4   select 'A2', null, null from dual union all
  5   select null, 'B1', null from dual union all
  6   select null, 'B2', null from dual union all
  7   select null, 'B3', null from dual union all
  8   select null, null, 'C1' from dual
  9  ),
 10  --
 11  ta as (select distinct a, dense_rank() over (order by a) rn from test where a is not null),
 12  tb as (select distinct b, dense_rank() over (order by b) rn from test where b is not null),
 13  tc as (select distinct c, dense_rank() over (order by c) rn from test where c is not null)
 14  --
 15  select ta.a, tb.b, tc.c
 16  from ta full outer join tb on ta.rn = tb.rn
 17          full outer join tc on ta.rn = tc.rn
 18  order by a, b, c
 19  /

A  B  C
-- -- --
A1 B1 C1
A2 B2
   B3

SQL>
0 голосов
/ 30 апреля 2020

Если у вас есть только одно значение на столбец, то я думаю, что более простое решение состоит в перечислении значений и агрегировании:

select max(a) as a, max(b) as b, max(c) as c
from (select t.*,
             dense_rank() over (partition by (case when a is null then 1 else 2 end),
                                             (case when b is null then 1 else 2 end),
                                             (case when c is null then 1 else 2 end)
                                order by a, b, c
                               ) as seqnum                                                 
      from t
     ) t
group by seqnum;

Это «агрегирует» только один раз и использует только одну оконную функцию, поэтому я думаю, что он должен иметь лучшую производительность, чем обработка каждого столбца в отдельности.

Другой подход заключается в использовании боковых объединений, которые доступны в Oracle 12 C - но это предполагает совместимость типов:

select max(case when which = 'a' then val end) as a,
       max(case when which = 'b' then val end) as b,
       max(case when which = 'c' then val end) as c      
from (select which, val,
             dense_rank() over (partition by which order by val) as seqnum
      from t cross join lateral
           (select 'a' as which, a as val from dual union all
            select 'b', b from dual union all
            select 'c', c from dual
           ) x
      where val is not null
     ) t
group by seqnum;

Производительность может быть сопоставимой, поскольку подзапрос удаляет так много строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...