Я обманываю с FOR XML
в SQL Server 2008, чтобы узнать, будет ли он лучше подходит для создания ответа веб-службы, а не полагаться на Hibernate & HQL для отображения DTO (или сопоставления их вручную из плоских результирующих наборов).Как избежать создания элемента переноса при ссылке на тип XML в SQL?
Я создал фиктивный пример, где люди могут иметь детей и набор телефонных номеров.
Я столкнулся с ситуацией, когда SELECT name FROM personCte
будет выдавать ненужную обертку <name>
, что приводит к <name><name first="test" last="test"/></name>
.
Я могу избавиться от дополнительного элемента упаковки, выполнив следующее, но мне интересно, есть ли более подходящий способ сделать это?
SELECT (select name)
FROM personCte
Одна проблема с этим решением является то, что он не может быть использован в КТР, поскольку все столбцы CTE должны быть названы.
Я также хотел бы знать, есть ли лучшие способы unflatten нескольких свойств в один элемент (например, firstName и lastName в имя), чем выполнение подзапроса?
Вот пример кода, я использую:
DECLARE @Person TABLE (
id int NOT NULL PRIMARY KEY IDENTITY(1, 1),
firstName nvarchar(50) NOT NULL,
lastName nvarchar(50) NOT NULL,
parentId int NULL
);
DECLARE @PersonPhoneNumber TABLE (
personId int NOT NULL,
number char(12) NOT NULL
);
INSERT INTO @Person (firstName, lastName, parentId)
VALUES
('Person', 'A', NULL),
('Person', 'B', 1),
('Person', 'C', 2);
INSERT INTO @PersonPhoneNumber
VALUES
(1, '888-888-8888'),
(1, '999-999-9999'),
(3, '333-333-3333');
;WITH personCte AS (
SELECT
id,
(
SELECT firstName AS [@first], lastName AS [@last]
FROM @Person
WHERE id = person.id
FOR XML PATH('name'), TYPE
) AS name,
(
SELECT number
FROM @PersonPhoneNumber
WHERE personId = person.id
FOR XML PATH(''), TYPE
) AS phoneNumbers,
parentId
FROM @Person person
)
SELECT
id,
(SELECT name), /* Used to avoid unwanted wrapping name element */
phoneNumbers,
parentId,
(
SELECT id, (SELECT name), phoneNumbers, parentId
FROM personCte person
WHERE parentId = p.id
FOR XML AUTO, TYPE
) AS children
FROM personCte p
FOR XML AUTO, ROOT('persons'), TYPE
Что правильно производит:
<persons>
<person id="1">
<name first="Person" last="A" />
<phoneNumbers>
<number>888-888-8888</number>
<number>999-999-9999</number>
</phoneNumbers>
<children>
<person id="2" parentId="1">
<name first="Person" last="B" />
</person>
</children>
</person>
<person id="2" parentId="1">
<name first="Person" last="B" />
<children>
<person id="3" parentId="2">
<name first="Person" last="C" />
<phoneNumbers>
<number>333-333-3333</number>
</phoneNumbers>
</person>
</children>
</person>
<person id="3" parentId="2">
<name first="Person" last="C" />
<phoneNumbers>
<number>333-333-3333</number>
</phoneNumbers>
</person>
</persons>
Является ли 'запрос' дорогостоящим вызовом с точки зрения производительности? По unflattening я имею в виду, что в базе данных у меня есть столбец firstName и lastName, но в фактическом XML я хочу элемент ' '. В настоящее время я использую вложенный запрос для достижения этого, но, возможно, есть лучший способ? –
plalx
Производительность 'query()' будет арахисами по сравнению с 'for xml auto'. Вы действительно должны избавиться от этого монстра и переписать все с помощью синтаксиса 'path()'. –
Кроме того, с помощью 'path()' вы можете определить более сложную структуру, иногда не прибегая к дополнительным подзапросам. В этом случае это будет нечто вроде: 'select p.id as [@Id], p.parentId как [@ParentId], p.firstName как [Name/@ First], p.lastName как [Name/@ Last ] от @Person p для xml path ('Person'), type, root ('Person'); ' –