Это решение, в котором я бы сказал, что оно будет работать во всех сценариях - хотя не гарантируется, что число, связанное с <Department>
узлом через ROW_NUMBER()
, будет отражать его реальное положение в любой ситуации ( см. примечания и ссылки ниже):
declare @myxml xml ='
<Departments>
<Department>
<Employee>
A
</Employee>
<Employee>
B
</Employee>
</Department>
<Department>
<Employee>
C
</Employee>
<Employee>
D
</Employee>
</Department>
</Departments>';
- Запрос будет использовать CTE для привязки чисел к первому уровню и передачи внутреннего узла в целом . Конечный SELECT будет использовать переданный узел <Department>
и выберет его сотрудников:
WITH NumberedDepartment AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS DepInx
,d.query(N'.') AS DepartmentNode
FROM @myxml.nodes(N'/Departments/Department') AS A(d)
)
SELECT DepInx
,e.value(N'text()[1]','nvarchar(max)') AS Employee
FROM NumberedDepartment
CROSS APPLY DepartmentNode.nodes(N'Department/Employee') AS B(e);
Если вы хотите прочитать о гарантии порядка сортировки , вы могли бы прочитать эту ветку . Особенно читабельны: В чате ниже Джон Каппеллеттис отвечает . Там я предоставляю подход, использующий XQuery
, и еще один подход, использующий таблицу подсчета / числа, чтобы выбрать элементы в их положении. Но это довольно сложно и медленно.
ОБНОВЛЕНИЕ: подход с гарантированным порядком сортировки
Этот подход позволит создать таблицу учета на лету . Если у вас есть таблица чисел, это было бы еще лучше ...
Предложение TOP
ограничит это число фактическим числом <Department>
узлов. Обязательно используйте исходную таблицу (я использую master..spt_values
), в которой есть как минимум столько строк, сколько вам может понадобиться.
При первом применении будет использоваться .query()
вместе с sql:column()
, чтобы получить правильный узел отдела для каждого номера. Второе заявление будет читать соответствующие сотрудники.
WITH Tally(Nmbr) AS
(
SELECT TOP (SELECT @myxml.value(N'count(/Departments/Department)','int'))
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM master..spt_values --just a pre-filled table with many rows
)
SELECT Nmbr
,e.value(N'text()[1]','nvarchar(max)') AS Employee
FROM Tally
OUTER APPLY(SELECT @myxml.query(N'/Departments/Department[sql:column("Nmbr")]')) AS A(ds)
OUTER APPLY ds.nodes(N'Department/Employee') AS B(e);