t-sql для создания XML-файла с использованием FOR XML Path, многоуровневые проблемы - PullRequest
1 голос
/ 03 октября 2019

Я создаю файл XML для загрузки в сторонний продукт. Файл должен начинаться с определенного уровня информации о файле и источнике, а затем за ним следуют конкретные требования к данным / уровни членов EVENT и CREW для этих событий.

Я могу создать начальный уровень с информацией о файле / источникеи у меня есть требования к данным в точности так, как они должны быть, но я не могу собрать их в одном файле между уровнем «ROOT» без повторения начального уровня между каждым уровнем EVENT или дополнительным уровнем EVENT, как если бы они были вложенными,Мне также удалось получить результат с уровнем ROW, который я не определил, и «теги» были изменены на &lt; и &gt: вместо <>. Я провел много исследований и попытался использовать метод объединения, подвыборы, методы вложения, а также множество комбинаций FOR XML PATH, AUTO, EXPLICIT, с элементами и без них. Я многому научился, но я просто не могу найти правильную комбинацию для нужных мне результатов.

Первый пример - это требуемый макет. Второй - один из примеров, который наиболее распространен для моих усилий, за которым следует SQL, который его создал.

каким он должен быть (уровень FILEINFO только один раз, только один уровень EVENT для каждого EVENT)

<ROOT>
    <FILEINFO>
      <SOURCE_ID>P</SOURCE_ID>
    </FILEINFO>
    <EVENT>
      <DATE>2019-09-24T08:00:00</DATE>
      <NO>1</NO>
      <DEL_FLAG>false</DEL_FLAG>
      <DATE_TIME_STAMP>2019-09-24T14:14:00</DATE_TIME_STAMP>
      <CREW>
        <LAST_NAME>DOE</LAST_NAME>
        <DEL_FLAG>false</DEL_FLAG>
        <DATE_TIME_STAMP>2019-09-24T14:14:00</DATE_TIME_STAMP>
      </CREW>
    </EVENT>
    <EVENT>
      <DATE>2019-09-16T12:30:00</DATE>
      <NO>1</NO>
      <DEL_FLAG>false</DEL_FLAG>
      <DATE_TIME_STAMP>2019-09-16T18:20:00</DATE_TIME_STAMP>
      <CREW>
        <LAST_NAME>DOE</LAST_NAME>
        <DEL_FLAG>false</DEL_FLAG>
        <DATE_TIME_STAMP>2019-09-16T18:20:00</DATE_TIME_STAMP>
      </CREW>
    </EVENT>
</ROOT>

что я получаю:

<ROOT>
  <EVENT>
    <FILEINFO>
      <SOURCE_ID>P</SOURCE_ID>
    </FILEINFO>
    <EVENT>
      <DATE>2019-09-16T08:00:00</DATE>
      <NO>1</NO>
      <DEL_FLAG>false</DEL_FLAG>
      <DATE_TIME_STAMP>2019-09-16T15:12:00</DATE_TIME_STAMP>
      <CREW>
        <LAST_NAME>DOE</LAST_NAME>
        <DEL_FLAG>false</DEL_FLAG>
        <DATE_TIME_STAMP>2019-09-16T15:12:00</DATE_TIME_STAMP>
      </CREW>
    </EVENT>
  </EVENT>
  <EVENT>
    <FILEINFO>
      <SOURCE_ID>P</SOURCE_ID>
    </FILEINFO>
    <EVENT>
      <DATE>2019-09-16T08:00:00</DATE>
      <NO>1</NO>
      <DEL_FLAG>false</DEL_FLAG>
      <DATE_TIME_STAMP>2019-09-16T15:12:00</DATE_TIME_STAMP>
      <CREW>
        <LAST_NAME>DOE</LAST_NAME>
        <DEL_FLAG>false</DEL_FLAG>
        <DATE_TIME_STAMP>2019-09-16T15:12:00</DATE_TIME_STAMP>
      </CREW>
    </EVENT>
  </EVENT>
... ...

самая последняя / самая простая попытка, которая создает выше:

SELECT 
    (SELECT SOURCE_ID FROM  (select 'P' as SOURCE_ID) FILEINFO ) AS 'FILEINFO/SOURCE_ID'
    ,[DATE]         AS 'EVENT/DATE'
    ,[NO]           AS 'EVENT/NO' 
    ,[DEL_FLAG]         AS 'EVENT/DEL_FLAG'
    ,[DATE_TIME_STAMP]  AS 'EVENT/DATE_TIME_STAMP'
    ,'DOE'          as 'EVENT/CREW/LAST_NAME'
    ,[DEL_FLAG2]        as 'EVENT/CREW/DEL_FLAG'
    ,[DATE_TIME_STAMP3]     as 'EVENT/CREW/DATE_TIME_STAMP'
FROM [dbo].XMLForFILEExport x 
FOR XML path('EVENT'), elements,  ROOT('ROOT')  ;

Ответы [ 2 ]

0 голосов
/ 04 октября 2019

Это просто, просто используйте вспомогательный выбор и действуйте так, как если бы это был * обычный столбец:

Этот простой SELECT вернет единственный <FILEINFO>

SELECT 'P' AS [FILEINFO/SOURCE_ID]
FOR XML PATH(''),ROOT('ROOT');

Вы видите, что я использовал пустой PATH(), но я установил ROOT().

Это результат

<ROOT>
  <FILEINFO>
    <SOURCE_ID>P</SOURCE_ID>
  </FILEINFO>
</ROOT>

Теперь мы можем начать добавлять ваши события. Сначала мне нужно таблица макетов для имитации вашей проблемы

DECLARE @mockupEventTable TABLE(ID INT IDENTITY,[NO] INT, [DATE] DATETIME, EventText VARCHAR(100));
INSERT INTO @mockupEventTable VALUES(1,'20190916','Event 1')
                                   ,(2,'20190917','Event 2');

- Запрос

SELECT 'P' AS [FILEINFO/SOURCE_ID]
      ,(
        SELECT e.[DATE]
              ,e.[NO]
              ,e.EventText
              ,'Doe' AS [CREW/LASTNAME]
        FROM @mockupEventTable e
        FOR XML PATH('EVENT'),TYPE
       ) AS [*] 
FOR XML PATH(''),ROOT('ROOT');

Результат

<ROOT>
  <FILEINFO>
    <SOURCE_ID>P</SOURCE_ID>
  </FILEINFO>
  <EVENT>
    <DATE>2019-09-16T00:00:00</DATE>
    <NO>1</NO>
    <EventText>Event 1</EventText>
    <CREW>
      <LASTNAME>Doe</LASTNAME>
    </CREW>
  </EVENT>
  <EVENT>
    <DATE>2019-09-17T00:00:00</DATE>
    <NO>2</NO>
    <EventText>Event 2</EventText>
    <CREW>
      <LASTNAME>Doe</LASTNAME>
    </CREW>
  </EVENT>
</ROOT>

ВыМожно увидеть, что суб-выбор создаст внутренний XML, как вам нужно. Мы должны указать ,TYPE, чтобы получить это как напечатанный XML. Попробуйте то же самое без. Вы получите XML экранированный , как если бы это был простой текст ...

И я указываю AS [*] (то же самое было AS [node()]), чтобы указать, что столбец "XML""не имеет собственного имени, но должен быть вставлен как . Это не обязательно (попробуйте без), но это делает вещи более читабельными ...

0 голосов
/ 03 октября 2019

Это потому, что вы уже указали ПУТЬ "СОБЫТИЕ". Также вы можете удалить EVENT в имени поля, например, «EVENT / CREW / DATE_TIME_STAMP» может быть просто «CREW / DATE_TIME_STAMP»

. Чтобы достичь того, что требуется, вы можете сгенерировать xml с элементами EVENT и затем вставить FILEINFO.

DECLARE @x xml;
SET @x=(SELECT 
    [DATE]         AS 'DATE'
    ,[NO]           AS 'NO' 
    ,[DEL_FLAG]         AS 'DEL_FLAG'
    ,[DATE_TIME_STAMP]  AS 'DATE_TIME_STAMP'
    ,'DOE'          as 'CREW/LAST_NAME'
    ,[DEL_FLAG2]        as 'CREW/DEL_FLAG'
    ,[DATE_TIME_STAMP3]     as 'CREW/DATE_TIME_STAMP'
FROM [dbo].XMLForFILEExport x 
FOR XML path('EVENT'), elements,  ROOT('ROOT'))


SET @x.modify('
insert <FILEINFO><SOURCE_ID>P</SOURCE_ID></FILEINFO>
as first
into (/ROOT)[1]');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...