Concat отличное значение в oracle sql

Как я могу объединить различные значения в oracle sql?

Моя структура таблицы выглядит следующим образом:

пользователь acc_1 acc_2 acc_3 acc_4 1 т1 т1 2 т2 т2 т2 3 т3
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

Я получаю вывод как:

пользователь согласно 1 т1, т1,, 2 t2 ,, t2, t2 3 , т3,,

Но мне не нужен дубликат соотв. Мне нужен мой вывод как:

пользователь согласно 1 т1 2 т2 3 т3

Это возможно?

В ваших примерных данных всегда есть один и тот же номер счета подряд. Всегда ли это так? Если да, то почему вам нужно конкатенировать, а не просто найти первое ненулевое значение? Если нет, то вам следует отредактировать свой вопрос и включить данные, где в строке есть разные номера счетов (и обратите внимание, что ответ, который вы приняли, НЕ будет объединять несколько различных значений; он найдет одно ненулевое значение а остальное проигнорю).

MT0 19.04.2023 11:25
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
1
55
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Самый простой способ - "отменить поворот" ваших данных и рассматривать их как строку для этого. Например:

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 здесь используется).

Littlefoot 19.04.2023 10:12

Учитывая примерные данные:

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;

Что выводит:

ПОЛЬЗОВАТЕЛЬ СЧЕТА 1 т1, 2 т2, 3 т3,

Примечание: если вы хотите удалить запятую в конце, вы можете использовать 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"

Что выводит:

ПОЛЬЗОВАТЕЛЬ СЧЕТА 1 т1 2 т2 3 т3

рабочий пример

Ответ принят как подходящий

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

select user, coalesce(acc_1, acc_2, acc_3, acc_4) as acc
from myTable

Но... coalesce не имеет ничего общего с конкатенацией

astentx 19.04.2023 11:12

Это не будет объединять значения. Он найдет первое ненулевое значение в списке столбцов и проигнорирует все следующие столбцы.

MT0 19.04.2023 11:15

@astentx, ОП хочет конкатенации? "Мне не нужен дубликат аккаунта"

jarlh 19.04.2023 11:15

Что ж, вот что делает плохо сформулированный вопрос и недостаточное количество выборочных данных. Название для меня ясно: Concat отличное значение в oracle sql

astentx 19.04.2023 11:16

Вопрос спрашивает: «Как я могу объединить разные значения в oracle sql?» Это не объединение и не поиск различных значений; он находит единственное ненулевое значение.

MT0 19.04.2023 11:16

Возможно, плохой выбор выборочных данных? Спросите OP для ясности и улучшений.

jarlh 19.04.2023 11:18

Другие вопросы по теме