#sql #xml #postgresql #xpath
Вопрос:
У меня есть некоторый XML в таблице (назовем его xml_table), мне нужно привести родителей с его детьми в идеальный порядок, но этого не происходит. Я упрощу задачу.
Это мой XML:
<group name="A">
<category target_id="1001">
<category flow_id="0" />
<category flow_id="1" />
<category flow_id="2" />
</category>
</group>
<group name="B">
<category target_id="1002">
<category flow_id="0" />
</category>
<category target_id="1003">
<category flow_id="0" />
</category>
<category target_id="1004">
<category flow_id="0" />
</category>
<category target_id="1005">
<category flow_id="0" />
</category>
</group>
<group name="C">
<category target_id="1006">
<category flow_id="0" />
<category flow_id="2" />
<category flow_id="4" />
</category>
<category target_id="1007">
<category flow_id="1" />
<category flow_id="6" />
</category>
<category target_id="1008">
<category flow_id="0" />
<category flow_id="1" />
<category flow_id="2" />
</category>
<category target_id="1009">
<category flow_id="0" />
<category flow_id="1" />
<category flow_id="2" />
<category flow_id="3" />
</category>
</group>
И это мой SQL:
SELECT unnest((xpath('@name', team)::text[])) AS group
,unnest((xpath('category/@target_id', team)::text[]::int[])) AS target_id
,unnest((xpath('category/category/@flow_id', team)::text[]::int[])) AS flow_id
FROM (
SELECT team::xml
FROM xml_table;
)
С помощью этого SQL я идеально подхожу для ГРУПП A и B. Когда в группе только 1 идентификатор цели и много идентификаторов потока (например, A)
Группа | Target_id | Flow_id |
---|---|---|
A | 1001 | 0 |
A | 1001 | 1 |
A | 1001 | 2 |
Работает Идеально
Когда у каждого target_id есть только один flow_id, не важно, много ли target_id, например, группа B.
Группа | Target_id | Flow_id |
---|---|---|
B | 1002 | 0 |
B | 1003 | 0 |
B | 1004 | 0 |
B | 1005 | 0 |
Works perfect too.
But in the group C doesn’t work, repeat many times the instance target_id — flow_id and even mix it, for example appear target_id with other flow_id than doesn’t belong (here repeat 3 times Target_id-Flow_id.
Group | Target_id | Flow_id |
---|---|---|
C | 1006 | 0 |
C | 1006 | 2 |
C | 1006 | 4 |
C | 1006 | 0 |
C | 1006 | 2 |
C | 1006 | 4 |
C | 1006 | 0 |
C | 1006 | 2 |
C | 1006 | 4 |
Смешайте тоже
Группа | Target_id | Flow_id |
---|---|---|
C | 1006 | 0 |
C | 1006 | 2 |
C | 1006 | 6 |
Flow_id = 6 является частью target_id = 1007 и отображается в target_id = 1006.
Это я хочу получить, та же структура XML, в которой хранится заказ.
Группа | Target_id | Flow_id |
---|---|---|
A | 1001 | 0 |
A | 1001 | 1 |
A | 1001 | 2 |
B | 1002 | 0 |
B | 1003 | 0 |
B | 1004 | 0 |
B | 1005 | 0 |
C | 1006 | 0 |
C | 1006 | 2 |
C | 1006 | 4 |
C | 1007 | 1 |
C | 1007 | 6 |
C | 1008 | 0 |
C | 1008 | 1 |
C | 1008 | 2 |
C | 1009 | 0 |
C | 1009 | 1 |
C | 1009 | 2 |
C | 1009 | 3 |
Комментарии:
1. Xpath не хватает контекста, я думаю , так и должно быть
//category/@target_id
,/group/@name
и//category/category/@flow_id
Ответ №1:
Выражения XPATH могут быть действительно неприятными при выполнении сложных задач. Мое предложение: Разделите операции на несколько подзапросов или CTE, чтобы упростить задачу. Это может дать вам некоторое вдохновение:
SELECT DISTINCT
g.group_id,
t.target_id,
unnest(xpath('//group[@name="'||g.group_id||'"]/category/category/@flow_id', team)::text[]) flow_id
FROM
xml_table x,
LATERAL unnest(xpath('//group/@name', x.team)::text[]) g (group_id),
LATERAL unnest(xpath('//group[@name="'||g.group_id||'"]/category/@target_id', team)::text[]) t (target_id)
ORDER BY g.group_id,t.target_id,flow_id;
ДЕМОНСТРАЦИЯ: db<>fiddle
Комментарии:
1. Спасибо, парень, за твой ответ, извини за поздний ответ. Сначала я нахожу другое решение, не по этапам, а не все вместе. В любом случае, ваш sql-это другой способ, чем я не знаю, спасибо за это. Но в XML есть 279 записей, и этот sql возвращает 450. Я не знаю почему, я посмотрю и проверю позже. В любом случае, это дает мне другую перспективу, спасибо!