Как вывести данные из одного столбца в одну строку через запятую?
Есть запрос, который выводит данные о заказах и пациентах:
select
fn_pat_name_by_id(p.keyid) AS fio
,TO_CHAR(p.birthdate,'dd.mm.yyyy') AS bd
,p_pat.address(p.keyid,1) addr
,s.text
from
research r
,order o
,service s
,patient p
where
o.research_id = r.id
and o.service_id = s.keyid
and r.patient_id = p.keyid
Как вывести данные в виде ФИО, Дата рождения, Адрес, Услуги, где данные в столбце услуги надо вывести как все услуги пациента в одну строку через запятую?
Пробовал так, но не помогает:
select
fn_pat_name_by_id(p.keyid) AS fio
,TO_CHAR(p.birthdate,'dd.mm.yyyy') AS bd
,p_pat.address(p.keyid,1) addr
,(select listagg(s.text, ',') within group (order by s.text) from service s where s.keyid = o.service_id) as usl
from
research r
,order o
,service s
,patient p
where
o.research_id = r.id
and o.service_id = s.keyid
and r.patient_id = p.keyid
И еще одно замечание, в столбце Услуги в итоге может получиться большой текст, поэтому нужен тип CLOB.
Ответы (2 шт):
SELECT
fn_pat_name_by_id(p.keyid) AS fio
,TO_CHAR(p.birthdate,'dd.mm.yyyy') AS bd
,p_pat.address(p.keyid,1) addr
,listagg(s.text, ', ') within GROUP (ORDER BY s.text) AS usl
FROM
research r
,order o
,patient p
,service s
WHERE
o.research_id = r.id
AND r.patient_id = p.keyid
AND s.keyid = o.service_id
GROUP BY p.keyid, p.birthdate
Получилось так.
Начать решение надо с создания минимального воспроизводимого примера. При этом, следует абстрагироваться от бизнес логики реальной задачи. Идёт речь, о пациентах и их процедурах, или о студентах и их лекциях, для технической стороны вопроса это не играет абсолютно никакой роли.
В вопросе простая связь таблиц многие-ко-многим. Надо сгрупировать значения из одной таблицы и вывести к ним лист связанных значений из другой таблицы.
Подготовим таблицы:
create table foo (id int, name varchar2 (8), created date)
/
create table bar (id int, text varchar2 (8))
/
create table foobar (fooid int, barid int)
/
Заполним их исходными данными:
insert all
when 1=1 then into foo values (rn, 'name'||rn, date'2020-01-01'+rn)
when 1=1 then into bar values (rn, 'text'||rn)
select rownum rn from dual connect by level<=3
/
insert into foobar
select foo.id, bar.id from foo, bar
/
Теперь запрос, который выводит все данные, выглядит так:
select
foo.name, foo.created, bar.text
from foo, foobar, bar
where foobar.fooid = foo.id
and foobar.barid = bar.id
/
NAME CREATED TEXT
-------- ------------------- --------
name1 2020-01-02 00:00:00 text1
name2 2020-01-03 00:00:00 text1
name3 2020-01-04 00:00:00 text1
[...]
name3 2020-01-04 00:00:00 text3
В итоге, запрос, который выведет желаемый результат:
select
foo.name, to_char (foo.created,'dd.mm.yyyy') created,
listagg (bar.text, ',') within group (order by bar.text) textlist
from foo
join foobar on foobar.fooid = foo.id
join bar on bar.id = foobar.barid
group by foo.name, foo.created
/
NAME CREATED TEXTLIST
-------- ---------- ------------------------
name1 02.01.2020 text1,text2,text3
name2 03.01.2020 text1,text2,text3
name3 04.01.2020 text1,text2,text3
Всё очень просто и понятно всем. Любой может скопировать команды выше и воспроизвести пример. Когда техническое решение станет понятно, то не составит особого труда заменить имена таблиц и колонок их реальными именами.