Страницы

Поиск по вопросам

понедельник, 6 января 2020 г.

Создание строки из значений (процедура)

#sql #oracle #plsql #plsql_developer


Добрый день. Т.к. от программирования далек, но в виду производственной необходимости
в это дело ввязался, прошу помочь с написанием процедуры в oracle plsql developer (буду
признателен за помощь в создании алгоритма так же).

Суть такова - есть первый столбец (условно ID, в моем контексте не уникальный), и
второй столбец, назову его "признаком". В базе это хранится в таком виде

ID  Признак
1   Красный
1   Темно-красный
2   Синий
2   Бирюзовый


Необходимо написать процедуру такого рода - все признаки, соответствующие одинаковому
ID, пишутся в одну ячейку. Т.е. так:

ID   Признак (применение процедуры)
1    Красный, (или ;) Темно-красный
2    Синий, Бирюзовый


Буду крайне признателен за помощь!
В виду необходимости скидываю сам кусок селекта:

(case when (row_number() over(partition by
    (select dd.name from metrology.document dd where dd.id in (select **max(d.document_id)**
from metrology.eqtype_document d where d.EQUIPMENT_TYPE_ID = e.id))
    order by e.name)) = 1 then
    (select dd.name from metrology.document dd where dd.id in (select **max(d.document_id)**
from metrology.eqtype_document d where d.EQUIPMENT_TYPE_ID = e.id)) end) as doc_name_to_form


Символами ** отмечен участок кода, из за которого возникает весь сыр-бор. 
Max там включен чисто для работоспособности - данный участок селекта возвращает более
одной строки и вызывает ошибку ora, поэтому я его max-ом искуссвенно урезал до одного
возвращаемого результата. Но дело в том, что в 70% случаев данный участок должен возвращать
более одного значения, для чего и необходима конкатенация, и я не знаю, как сюда инъектировать
какой либо код.
    


Ответы

Ответ 1



Как вариант, если не заработают wm_conat или sys_xmlagg, сборка рекурсивным CTE: with Src(ID, Color, RN) as( select ID, Color, row_number() over(partition by ID order by NULL) RN from tab ), Tree(ID,color,RN) as( select ID, Color, RN from Src where RN=1 union all select T.ID,T.Color||','||S.Color,S.RN from Tree T, Src S where S.ID=T.ID and S.RN=T.RN+1 ) select * from Tree Или такой вариант (при наличии sys_connect_by_path): select ID, substr(max(sys_connect_by_path(Color,',')),2) from ( select ID, Color, row_number() over(partition by ID order by NULL) RN from tab ) start with RN=1 connect by ID=prior ID and RN=prior RN+1 group by Id Или сделать функцию, получающую строку по ID, что возможно удобнее для применения в выходных формах: create or replace function get_colors(ID_ number) return varchar2 is result varchar2(4000); begin result:=NULL; for C in(select accname from v1users where vidid=ID_) loop if length(result)+length(C.accname) > 3996 then return substr(result||',...',2); end if; result:=result||','||C.accname; end loop; return substr(result,2); end;

Ответ 2



Получить нужный результат можно таким запросом: select id, to_char(wm_concat("Признак")) as "Признак" from table group by id Следует заметить, что wm_concat функция недокументированная и в проме ее использовать не всегда разумно. Если wm_concat не подходит, можно использовать XML: select id, CAST(RTRIM(Sys_xmlagg(XMLELEMENT(col, id||', ')).extract('/ROWSET/COL/text()').getclobval(), ', ') AS VARCHAR2(4000)) as "Признак" FROM table group by id col - это Ваша колонка Признак. Использовать русское наименование колонки у меня не получилось. В обоих вариантах могут быть проблемы с сортировкой значений.

Комментариев нет:

Отправить комментарий