Вы ищете что-то подобное?
DECLARE @xml XML=
N'<xml>
<entities>
<entity id="147297" version="20150209161956">
<dobs>
<dob Y="1970">10/16/1970</dob>
<dob D="17" M="10" Y="1970">10/17/1970</dob>
<dob D="02" M="7" Y="1920">02/1]7/1920</dob>
<dob D="1" M="9" Y="1990">10/9/1990</dob>
<dob Y="1870">10/16/1870</dob>
</dobs>
</entity>
</entities>
</xml>';
- полные добы для таблицы A
SELECT ent.value('@id','int') AS Entity_Id
,ent.value('@version','nvarchar(max)') AS Entity_Version
,AllParams.query('.')
FROM @xml.nodes('/xml/entities/entity') A(ent)
OUTER APPLY A.ent.nodes('dobs/dob[@D and @M and @Y]') B(AllParams);
- добы только Y для таблицы B
SELECT ent.value('@id','int') AS Entity_Id
,ent.value('@version','nvarchar(max)') AS Entity_Version
,JustY.query('.')
FROM @xml.nodes('/xml/entities/entity') A(ent)
OUTER APPLY A.ent.nodes('dobs/dob[@Y and empty(@M)]') C(JustY);
Оба запроса используют предикат XQuery в .nodes()
. Первый запрос вернет <dob>
узлов, в которых есть D-, M- и Y-атрибуты. Второй запрос вернет <dob>
узлов, где M-атрибут пуст (=> не существует).
Легко собрать значения для вашей вставки. Просто используйте .value()
вместо .query()
и запросите атрибут, используя, например, @Y
, или запросите содержимое узла, используя text()
:
--complete dobs for Table A
SELECT ent.value('@id','int') AS Entity_Id
,ent.value('@version','nvarchar(max)') AS Entity_Version
,AllParams.value('@D','int') TheDay
,AllParams.value('@M','int') TheMonth
,AllParams.value('@Y','int') TheYear
,AllParams.value('text()[1]','nvarchar(max)') TheContent
FROM @xml.nodes('/xml/entities/entity') A(ent)
OUTER APPLY A.ent.nodes('dobs/dob[@D and @M and @Y]') B(AllParams);
Подсказка: внутри XML any значение даты / времени должно быть в кодировке ISO8601 (например, 1970-10-17
). В противном случае вы открыты для смешения культур ... Более того: с ISO8601 вы можете использовать date
в качестве типа данных в .value()
, чтобы получить безопасное значение. Без этого вы подвержены ошибкам при приведении ...