Как я могу объединить различные значения в oracle sql?
Моя структура таблицы выглядит следующим образом:
create table myTable (user, acc_1, acc_2,acc_3,acc_4) as
select 1, t1, t1, null,null from dual union all
select 2, t2, null, t2,t2 from dual union all
select 3, null, t3, null,null from dual ;
когда я запускаю запрос:
select user, acc_1 || ','||acc_2||','||acc_3||','||acc_4 as acc
from myTable
Я получаю вывод как:
Но мне не нужен дубликат соотв. Мне нужен мой вывод как:
Это возможно?
Самый простой способ - "отменить поворот" ваших данных и рассматривать их как строку для этого. Например:
with unpivot_data as (
select user_, acc_1 acc from myTable where acc_1 is not null
union all
select user_, acc_2 from myTable where acc_2 is not null
union all
select user_, acc_3 from myTable where acc_3 is not null
union all
select user_, acc_4 from myTable where acc_4 is not null
)
select user_, listagg(distinct acc, ', ')
from unpivot_data
group by user_
Здесь я преобразовал ваши данные в строки и использовал LISTAGG(DISTINCT ...)
, чтобы соединить их, как описано.
Демо здесь.
Очевидно, вы также можете использовать здесь UNPIVOT
.
Обновлено: как правильно указал @Littlefoot, предлагаемое решение не будет работать для более старых версий Oracle. Для них можно использовать UNION
вместо UNION ALL
и пропустить DISTINCT
в функции агрегации.
with unpivot_data as (
select user_, acc_1 acc from myTable where acc_1 is not null
union
select user_, acc_2 from myTable where acc_2 is not null
union
select user_, acc_3 from myTable where acc_3 is not null
union
select user_, acc_4 from myTable where acc_4 is not null
)
select user_, listagg(acc, ', ') WITHIN GROUP (order by acc)
from unpivot_data
group by user_
На самом деле, если вы поместите UNION (вместо UNION ALL), то LISTAGG не понадобится DISTINCT (который не поддерживается, например, в 11g) (и мы не знаем, какая версия Oracle здесь используется).
Учитывая примерные данные:
create table myTable ("USER", acc_1, acc_2,acc_3,acc_4) as
select 1, 't1', 't1', null, null from dual union all
select 2, 't2', null, 't2', 't2' from dual union all
select 3, null, 't3', null, null from dual;
Вы можете использовать выражения CASE
(которые требуют большего ввода, но требуют только одного сканирования таблицы и используют простые и быстрые сравнения):
SELECT "USER",
CASE WHEN acc_1 IS NOT NULL
THEN acc_1 || ',' END
|| CASE WHEN acc_2 IS NOT NULL
AND (acc_1 IS NULL OR acc_1 <> acc_2)
THEN acc_2 || ',' END
|| CASE WHEN acc_3 IS NOT NULL
AND (acc_1 IS NULL OR acc_1 <> acc_3)
AND (acc_2 IS NULL OR acc_2 <> acc_3)
THEN acc_3 || ',' END
|| CASE WHEN acc_4 IS NOT NULL
AND (acc_1 IS NULL OR acc_1 <> acc_4)
AND (acc_2 IS NULL OR acc_2 <> acc_4)
AND (acc_3 IS NULL OR acc_3 <> acc_4)
THEN acc_4 || ',' END AS accounts
FROM myTable;
Что выводит:
Примечание: если вы хотите удалить запятую в конце, вы можете использовать RTRIM
(или SUBSTR
до предпоследнего символа, если номера счетов могут содержать запятые).
или развернуть и повторно агрегировать строки (что намного меньше для ввода, но будет менее эффективно разводить, а затем повторно агрегировать по сравнению с выполнением всего этого в начальных строках с выражениями CASE
):
SELECT "USER",
LISTAGG(DISTINCT acc) WITHIN GROUP (ORDER BY type) AS accounts
FROM myTable
UNPIVOT (acc FOR type IN (acc_1, acc_2, acc_3, acc_4))
GROUP BY "USER"
Что выводит:
Просто используйте COALESCE
, чтобы выбрать первое ненулевое значение счета для каждого пользователя:
select user, coalesce(acc_1, acc_2, acc_3, acc_4) as acc
from myTable
Но... coalesce
не имеет ничего общего с конкатенацией
Это не будет объединять значения. Он найдет первое ненулевое значение в списке столбцов и проигнорирует все следующие столбцы.
@astentx, ОП хочет конкатенации? "Мне не нужен дубликат аккаунта"
Что ж, вот что делает плохо сформулированный вопрос и недостаточное количество выборочных данных. Название для меня ясно: Concat отличное значение в oracle sql
Вопрос спрашивает: «Как я могу объединить разные значения в oracle sql?» Это не объединение и не поиск различных значений; он находит единственное ненулевое значение.
Возможно, плохой выбор выборочных данных? Спросите OP для ясности и улучшений.
В ваших примерных данных всегда есть один и тот же номер счета подряд. Всегда ли это так? Если да, то почему вам нужно конкатенировать, а не просто найти первое ненулевое значение? Если нет, то вам следует отредактировать свой вопрос и включить данные, где в строке есть разные номера счетов (и обратите внимание, что ответ, который вы приняли, НЕ будет объединять несколько различных значений; он найдет одно ненулевое значение а остальное проигнорю).