Я застрял при создании XML-документа (IDOC) из выбора SQL.
XML должен выглядеть так:
<IDOC>
<MASTER>
.... some master elements ...
<NESTED1>
... 1st nested element instance 1...
</NESTED1>
<NESTED1>
... 1st nested element instance 2...
</NESTED1>
<NESTED2>
... instance 1
</NESTED2>
<NESTED2>
... instance 2
</NESTED2>
</MASTER>
<IDOC>
Но я получаю следующее:
<IDOC>
<MASTER>
.... some master elements ...
<NESTED1>
... 1st nested element instance 1...
</NESTED1>
<NESTED2>
... instance 1
</NESTED2>
</MASTER>
<IDOC>
<IDOC>
<MASTER>
.... some master elements ...
<NESTED1>
... 1st nested element instance 1...
</NESTED1>
<NESTED2>
... instance 2
</NESTED2>
</MASTER>
<IDOC>
<IDOC>
<MASTER>
.... some master elements ...
<NESTED1>
... 1st nested element instance 2...
</NESTED1>
<NESTED2>
... instance 1
</NESTED2>
</MASTER>
<IDOC>
<IDOC>
<MASTER>
.... some master elements ...
<NESTED1>
... 1st nested element instance 2...
</NESTED1>
<NESTED2>
... instance 2
</NESTED2>
</MASTER>
<IDOC>
Набор данных SQL, генерирующий XML, выглядит следующим образом:
select
MASTER.COL1 as 'MASTER/COL1',
MASTER.COL2 as 'MASTER/COL2',
NESTED1.DATA1 as 'MASTER/NESTED1/DATA1',
NESTED2.TEXT1 as 'MASTER/NESTED2/TEXT1',
from MASTER
join NESTED1 on NESTED1.MASTER_PK = MASTER.MASTER_PK
join NESTED2 on NESTED2.MASTER_PK = MASTER.MASTER_PK
for xml PATH, ROOT('IDOC')
Возможно, я не правильно прочитал документацию, но я не нашел ни одного примера, возможно ли то, что мне нужно, и какие директивы или параметры следует использовать.
Что касается минимально воспроизводимого примера, связанного с https://dbfiddle.uk/eZWVmVKL:
желаемый результат будет:
<MASTER>
<ID>158</ID>
<NAME>Antenna</NAME>
<DESCRIPTION>
<LANG>CZ</LANG>
<TEXT>Antena Yagi 6el</TEXT>
</DESCRIPTION>
<DESCRIPTION>
<LANG>EN</LANG>
<TEXT>Antenna Yagi 6 elements</TEXT>
</DESCRIPTION>
<PERFORMANCE>
<PARAM>GAIN</PARAM>
<UNIT>dBi</UNIT>
<VALUE>8.5</VALUE>
</PERFORMANCE>
<PERFORMANCE>
<PARAM>F/B RATIO</PARAM>
<UNIT>dB</UNIT>
<VALUE>15</VALUE>
</PERFORMANCE>
<PERFORMANCE>
<PARAM>LENGTH</PARAM>
<UNIT>cm</UNIT>
<VALUE>120</VALUE>
</PERFORMANCE>
</MASTER>
Недоразумение, @YitzhakKhabinsky. Я создал общий пример, чтобы не разглашать зарезервированную информацию о компании. Например, NESTED1 и NESTED2 могут быть ЧАСТЯМИ и ЦВЕТАМИ. То же самое относится к DATA1, TEXT1. Это примеры имен элементов, не связанные с порядком или значениями данных.
Задавая вопрос, вам необходимо предоставить минимальный воспроизводимый пример: (1) DDL и образец набора данных, т. е. таблицы CREATE плюс инструкции INSERT T-SQL. (2) Что вам нужно сделать, т. е. логику и попытку реализации вашего кода в T-SQL. (3) Желаемый результат, основанный на примере данных в пункте 1 выше. (4) Версия вашего SQL-сервера (ВЫБЕРИТЕ @@version;).
Пожалуйста, предоставьте минимальный воспроизводимый пример, и мы предоставим вам работающее решение через T-SQL. Ответ, который вы отметили как Ответ, не является Ответом без рабочего кода.
Пожалуйста, предоставьте минимальный воспроизводимый пример: ##1-4. Решением является сочетание T-SQL и XQuery. Мы принимаем вызов!
Спасибо за dbfiddle. Увы, он охватывает только ##1,4. Пожалуйста, отредактируйте свой вопрос и добавьте № 3: Желаемый результат на основе примеров данных.
Я предоставил черновой вариант ответа. Все еще ждем желаемого результата.
Вы не группируете по MASTER.MASTER_PK, поэтому вы получаете 1 строку для каждого кортежа (master, вложенный1, вложенный2), сгенерированного вашими соединениями JOIN. Как только вы сгруппируете по MASTER.MASTER_PK, у вас возникнет еще одна проблема: вы получите перекрестное произведение все NESTED1 и NESTED2 связаны с этим MASTER_PK, поэтому решение состоит в том, чтобы сгенерировать список узлов «NESTED1» и «NESTED2» с подзапросами, агрегирующими результаты в узле MASTER.
P.S. поэтому мне приходится создавать наборы встроенных элементов отдельно, а затем искать другой способ составления окончательного XML; я полагаю, что в MS-SQL это не поддерживается.
@p3consulting, можно ли переработать ваш ответ и предоставить работающий код T-SQL?
Извините, я недостаточно свободно владею диалектом SQLServer, когда дело касается генерации XML (или JSON).
Небольшой и неполный (отсутствует уровень IDOC) POC: dbfiddle.uk/NaqrgaP8 ... пришлось использовать FOR XML EXPLICIT, чтобы получить то, что я хотел, но я плохо разбираюсь в SQLServer, может быть, есть что-то проще (к вашему сведению, в ОРА: dbfiddle.uk/hoNnewkh)
Упрощенная версия для SQLServer: dbfiddle.uk/9ZlkhoRq
Попробуйте следующее решение на основе T-SQL и XQuery.
Он следует той же парадигме минимальных воспроизводимых примеров. Вы копируете его в SSMS как есть, запускаете, и он работает как положено, выдавая желаемый результат.
SQL
USE tempdb;
GO
-- DDL and sample data population, start
DROP TABLE IF EXISTS popis;
DROP TABLE IF EXISTS master;
DROP TABLE IF EXISTS performance;
CREATE TABLE master (
master_pk int identity(1,1) primary key,
item_id int,
item_name varchar(50)
);
INSERT INTO master VALUES
( 158, 'Antenna');
create table popis (
master_pk int,
POPIS_PK int identity(1,1) primary key,
LANG varchar(3),
TEXT varchar(50)
);
insert into popis values
(1, 'CZ', 'Antena Yagi 6el'),
(1, 'EN', 'Antenna Yagi 6 elements');
create table performance (
master_pk int,
performance_pk int identity(1,1),
param varchar(50),
unit varchar(10),
value numeric(8,3)
);
insert into performance
values (1, 'GAIN', 'dBi', 8.5),
(1, 'F/B RATIO', 'dB', 15),
(1, 'LENGTH', 'cm', 120);
-- DDL and sample data population, end
SELECT m.item_id AS [ID], m.item_name AS [NAME]
, (SELECT po.LANG, po.TEXT
FROM popis AS po
WHERE po.master_pk = m.master_pk
FOR XML PATH('DESCRIPTION'), TYPE)
, (SELECT pe.param AS [PARAM], pe.unit AS [UNIT], pe.value AS [VALUE]
FROM performance AS pe
WHERE pe.master_pk = m.master_pk
FOR XML PATH('PERFORMANCE'), TYPE)
FROM dbo.master AS m
FOR XML PATH(''), TYPE, ROOT('MASTER');
Выход
<MASTER>
<ID>158</ID>
<NAME>Antenna</NAME>
<DESCRIPTION>
<LANG>CZ</LANG>
<TEXT>Antena Yagi 6el</TEXT>
</DESCRIPTION>
<DESCRIPTION>
<LANG>EN</LANG>
<TEXT>Antenna Yagi 6 elements</TEXT>
</DESCRIPTION>
<PERFORMANCE>
<PARAM>GAIN</PARAM>
<UNIT>dBi</UNIT>
<VALUE>8.500</VALUE>
</PERFORMANCE>
<PERFORMANCE>
<PARAM>F/B RATIO</PARAM>
<UNIT>dB</UNIT>
<VALUE>15.000</VALUE>
</PERFORMANCE>
<PERFORMANCE>
<PARAM>LENGTH</PARAM>
<UNIT>cm</UNIT>
<VALUE>120.000</VALUE>
</PERFORMANCE>
</MASTER>
ну это точно НЕ нужный формат так как записей больше одной и мастер повторяется
Надеюсь, теперь вы понимаете важность минимального воспроизводимого примера. Все четыре №№ 1–4 очень важны. Мне нужен от вас номер 3 – желаемый результат. Пожалуйста, отредактируйте свой исходный вопрос и добавьте все ##1-4 без dbfiddler. Прямо в исходном вопросе.
Была ли у вас возможность опробовать предложенное решение?
Встраивание последовательных чисел в имена элементов XML считается плохой практикой. Если вам действительно нужны последовательные номера, лучше использовать для этого атрибуты. А также следующее:
<root><row id=1>...</row><row id=2>...</row></root>