oronsultan Ответов: 1

Изменение атрибута XML в зависимости от другого атрибута


Эй ребята,
вот мой вопрос:
я вызываю хранимую процедуру, которая получает xml в качестве параметра.
вот xml, который я отправляю:
<Root>
  <Categories>
    <TopCategory></TopCategory>
    <MediumCategory></MediumCategory>
    <SubCategory>tomato</SubCategory>
  </Categories>
  <Categories>
    <TopCategory></TopCategory>
    <MediumCategory></MediumCategory>
    <SubCategory>banana</SubCategory>
  </Categories>
  <Categories>
    <TopCategory></TopCategory>
    <MediumCategory></MediumCategory>
    <SubCategory>apple</SubCategory>
  </Categories>
<Root>


в СП, я хочу перебрать узлы, используя курсор и узлов по каждому элементу ,
получение значения<SubCategory & gt; и serach в других таблицах (tblMediumCategory, tblTopCategory) для вставки значения.
В конце концов, я хочу вернуть xml в качестве вывода.
то, что я сейчас делаю, - это преобразование xml в таблицу, и с помощью курсора Я успешно могу получить все подкатегории.
Проблема в том, когда я хочу обновить узел. я не знаю, как установить предложение WHERE, я не знаю, как сказать sql обновить определенный etc <TopCategory> where <SubCategory> = BlaBla.
Вот как выглядит SP до сих пор:
ALTER PROCEDURE [dbo].[SP_GetCategories]
@xmlCat xml
AS
BEGIN
--===============================
DECLARE @str nvarchar(max)
DECLARE @tmpMedium nvarchar(50), @tmpTop nvarchar (50)
DECLARE @idoc INT
declare @tmpTbl table(id int, parentId int, nodetype int, localname nvarchar(max), prefix nvarchar(max), namespaceuri nvarchar(max), datatype nvarchar(max), prev int, [text] nvarchar(max))
--===============================
EXEC sys.sp_xml_preparedocument @idoc OUTPUT, @xmlCat
--===============================
INSERT INTO @tmpTbl SELECT * FROM OPENXML (@idoc, '/Root', 2)
--===============================
DECLARE MY_CURSOR CURSOR 
  LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR 
SELECT DISTINCT t.text
FROM @tmpTbl t
--===============================
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @str
WHILE @@FETCH_STATUS = 0
BEGIN 
--===============================
SELECT @tmpMedium = m.CategoryName, @tmpTop = t.CategoryName 
FROM tblSubSources s
JOIN tblMediumSources m
ON s.MediumSourceId = m.CategoryId
JOIN tblTopSources t
ON m.TopCategoryId = t.CategoryId
WHERE s.SubSourceName = @str
--===============================
SET  @xmlCat.modify('replace value of (/Rows/Categorys/@TopCategory)[1] with sql:variable("@tmpTop")')
************************************This is where the <WHERE> Clause suppouse to be!!!!!!!!!!!!!!!!**********************************
--===============================
FETCH NEXT FROM MY_CURSOR INTO @str
--===============================
END
--===============================
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
--===============================
EXEC SYS.SP_XML_REMOVEDOCUMENT @idoc
--===============================
END


Кто-нибудь может мне помочь, пожалуйста?

Что я уже пробовал:

.............................................

Homero Rivera

Комментарий, Ваш XML-файл не совсем точно закрыт. последний элемент должен быть /Root

1 Ответов

Рейтинг:
6

Homero Rivera

Хотя возможно использовать XQuery в последних версиях SQL Server (я думаю, с 2012 года), то, что вы пытаетесь сделать, имеет высокую дозу накладных расходов и поэтому неэффективно.

Я бы вставил XML в таблицу @temp, объединил ее с другими таблицами, чтобы обновить ее, а затем выбрал из таблицы @temp с помощью for XML AUTO ROOT('Root'), так как вы говорите, что хотите вернуть XML в качестве вывода.

Хотя я не знаю дизайна вашей базы данных, сосредоточьтесь только на идеях. Этот код должен быть не менее чем на 90% тем, что вам нужно

/*

This is pretty much your XML that you want to update, right?

<Root>
  <Categories>
    <TopCategory></TopCategory>
    <MediumCategory></MediumCategory>
    <SubCategory>tomato</SubCategory>
  </Categories>
  <Categories>
    <TopCategory></TopCategory>
    <MediumCategory></MediumCategory>
    <SubCategory>banana</SubCategory>
  </Categories>
  <Categories>
    <TopCategory></TopCategory>
    <MediumCategory></MediumCategory>
    <SubCategory>apple</SubCategory>
  </Categories>
</Root>
*/


ALTER PROCEDURE [dbo].[SP_GetCategories]
@xmlCat xml
AS
BEGIN


DECLARE @idoc INT;

DECLARE @tmpTbl table(
id INT IDENTITY(1, 1) PRIMARY KEY --you always want a uniquer identifier, right?
, TopCategory NVARCHAR(100)
, MediumCategory NVARCHAR(100)
, SubCategory NVARCHAR(100)
);


EXEC sys.sp_xml_preparedocument @idoc OUTPUT, @xmlCat;

INSERT INTO @tmpTbl (TopCategory, MediumCategory, SubCategory)
SELECT TopCategory, MediumCategory, SubCategory 
FROM OPENXML (@idoc, '/Root/Categories', 2)
WITH (
TopCategory NVARCHAR(100) 'TopCategory' --Mapping to the exact element name is optional
, MediumCategory NVARCHAR(100) 'MediumCategory' --if your elements are always present on the right place
, SubCategory NVARCHAR(100) 'SubCategory'
);

--you already have your data, no need to keep this in the engine
EXEC SYS.SP_XML_REMOVEDOCUMENT @idoc;


--I'M NOT 100% SURE THIS ONE IS RIGHT, YOU'LL BE THE BEST JUDGE
--JUST FOCUS ON THE IDEA BEHIND
WITH Categories AS (
SELECT m.CategoryName AS MediumCategory, t.CategoryName AS TopCategory, s.SubSourceName
FROM tblSubSources s
JOIN tblMediumSources m ON s.MediumSourceId = m.CategoryId
JOIN tblTopSources t ON m.TopCategoryId = t.CategoryId
)
UPDATE temp
SET TopCategory = c.TopCategory
	, MediumCategory = c.MediumCategory
FROM @tmpTbl temp
INNER JOIN Categories c ON temp.SubCategory = c.SubSourceName;


--NOW your @tmpTbl is updated with the values you needed
--time to output the table as XML
SELECT 
TopCategory
, MediumCategory
, SubCategory
FROM @tmpTbl AS Categories
FOR XML AUTO, ELEMENTS, ROOT('Root')


END



Совет
Совсем недавно у меня была большая борьба с XML-документом, но документ победил.
При отображении элементов это просто не сработало бы.
Передача XML в хранимой процедуре не работает.

XML чувствителен к регистру, поэтому я называл элементы неправильными именами с такими простыми различиями, как "RowID" и "RowId".
Будьте очень осторожны при отображении элементов.


oronsultan

Дорогой Гомеро,
Я только что закончил работу над вашим решением. Я закончил, когда хлопнул в ладоши перед экраном! Аплодисменты были для вас: -). Большое вам спасибо за это решение, я очень ценю его. Это действительно помогло мне. Кстати, я получил ваш совет о чувствительном к регистру регистре, но просто чтобы вы знали, XML, который я загрузил, пропустил узел currect. На практике это выглядит так:, но я узнал кое-что новое. Большое спасибо!! Огромное решение!

Homero Rivera

С удовольствием! Это было действительно хорошее упражнение для моего предстоящего сертификационного экзамена :)