У меня есть следующая таблица:

Сотрудник (id int, name varchar, managerid int)

   ID   NAME   MANAGERID
    1    A       2
    2    B       4
    3    C       4
    4    D      NULL

Желаемый результат:

<Node name="D" id="4">
   <Node name="B" id="2">
    <Node name="A" id="1">
    </Node>
   </Node>  
  <Node name="C" id="3">
  </Node>
</Node>

Теперь я знаю, что это не что иное, как Поиск в глубину , поэтому я сделал следующее:

WITH t1(id,name,managerid) AS (
  -- Anchor member.
  SELECT id,
         name,
         managerid
  FROM   employee
    WHERE  managerid IS NULL
  UNION ALL
  -- Recursive member.
  SELECT t2.id,
         t2.name,
         t2.managerid
  FROM   employee t2, t1
  WHERE  t2.managerid = t1.id
)
SEARCH DEPTH FIRST BY id SET order1
SELECT id,
       name,
       managerid
FROM   t1
ORDER BY order1\\

И вывод вышеуказанного запроса:

   ID  NAME MANAGERID
    4   D    NULL
    2   B    4
    1   A    2
    3   C    4

Теперь я не знаю, как преобразовать этот вывод в версию xml, показанную ранее.

Я знаю, что есть такие функции, как XMLElement, XMLAGG и т. Д., Но я не знаю, как использовать их в такого рода иерархических запросах.

Примечание. В настоящее время я делаю это в Oracle , но если у другой СУБД есть более простой способ решить эту проблему, то я полностью за.

0
Harshil Doshi 13 Мар 2018 в 17:44

2 ответа

Лучший ответ

Вы можете сделать это с помощью DBMS_XMLGEN.newcontextfromhierarchy и CTE, если вы имитируете столбец level из connect by:

SELECT DBMS_XMLGEN.getXML(DBMS_XMLGEN.newcontextfromhierarchy('
with employee as (
  select 1 id, ''A'' name, 2 managerid from dual union all
  select 2 id, ''B'' name, 4 managerid from dual union all
  select 3 id, ''C'' name, 4 managerid from dual union all
  select 4 id, ''D'' name, null managerid from dual 
)
, t1(lvl,id,name,managerid) AS (
  -- Anchor member.
  SELECT 1 as lvl,
         id, 
         name,
         managerid
  FROM   employee
    WHERE  managerid IS NULL
  UNION ALL
  -- Recursive member.
  SELECT t1.lvl+1 as lvl, 
         t2.id, 
         t2.name,
         t2.managerid
  FROM   employee t2, t1
  WHERE  t2.managerid = t1.id
)
SEARCH DEPTH FIRST BY id SET order1
SELECT lvl, xmlelement("Node", xmlattributes(name AS "name", id AS "id"))
FROM   t1
ORDER BY order1
')) 
FROM dual

вывод

<?xml version="1.0"?>
<Node name="D" id="4">
  <Node name="B" id="2">
    <Node name="A" id="1"/>
  </Node>
  <Node name="C" id="3"/>
</Node>
1
wolfrevokcats 14 Мар 2018 в 11:28

Вы можете сделать это с помощью dbms_xmlgen.newcontextFromHierarchy, например:

select dbms_xmlgen.getxmltype(dbms_xmlgen.newcontextFromHierarchy('
WITH sample_data AS (SELECT 1 ID, ''A'' NAME, 2 managerid FROM dual UNION ALL
                     SELECT 2 ID, ''B'' NAME, 4 managerid FROM dual UNION ALL
                     SELECT 3 ID, ''C'' NAME, 4 managerid FROM dual UNION ALL
                     SELECT 4 ID, ''D'' NAME, NULL FROM dual)
select level 
       , xmlelement("node" 
       , XMLAttributes(name as "name",
                       id as "id")
       ) 
FROM   sample_data
CONNECT BY PRIOR ID = managerid
START WITH managerid IS NULL
  ')) from dual;

Который возвращает:

<?xml version="1.0"?>
<node name="D" id="4">
  <node name="B" id="2">
    <node name="A" id="1"/>
  </node>
  <node name="C" id="3"/>
</node>

Вам нужно будет заменить запрос внутри вызова dbms_xmlgen.newcontextFromHierarchy() вашим фактическим запросом.

2
Boneist 14 Мар 2018 в 10:12