Best practice:
- Only update XML / records that require updating.
(i.e., avoid updating all records regardless of whether the data is different or not). - ONLY updates XML / reports once.
(for example, do not delete each Node, and then go back and insert each Node). - Increase productivity with minimal impact.
(i.e., avoid inserting or deleting nodes when a simple "Replace" or "Insert-text" is executed. - Do not risk losing other important data.
(i.e., NEVER delete Node and risk losing potential children when everything you do updates the text value). - Create something reusable that will work for each scenario.
(i.e. the question asks us how to do this when you already know the unique identifier.
However, create your answer to handle multiple records in the most efficient way).
XML Column
This is how I would script it to update the XML field in the table:
DECLARE @newValue nVarChar(128) = '01' --Insert a Value when the Element is Empty (ie <AgencyID />), so it becomes <AgencyID>01<\AgencyID>. UPDATE dbo.UploadReport SET XmlTest.modify('insert text{sql:variable("@newValue")} as first into (/CodeFiveReport/Owner/AgencyID)[1]') WHERE XmlTest.value('(/CodeFiveReport/Owner/AgencyID)[1]', 'nVarChar(128)') = ''--Node is: <AgencyID /> AND id = 'myId' --Replace the Value if Text already Exists AND is Different (eg <AgencyID>99<\AgencyID>). -- Note: This will not work for Empty-Elements (ie <AgencyID />), which is why we perform the Update Above. UPDATE dbo.UploadReport SET XmlTest.modify('replace value of (/CodeFiveReport/Owner/AgencyID)[1] with sql:variable("@newValue")') WHERE XmlTest.value('(/CodeFiveReport/Owner/AgencyID)[1]', 'nVarChar(128)') != @newValue--Node is like: <AgencyID>99<\AgencyID> AND id = 'myId' --Optional. Use the Update below if it is possible for an Element to not exist at all. UPDATE dbo.UploadReport SET XmlTest.modify('insert <AgencyID>{sql:variable("@newValue")}</AgencyID> as first into (/CodeFiveReport/Owner)[1]') WHERE XmlTest.exist('/CodeFiveReport/Owner/AgencyID') = 0--The AgencyID Element/Node is missing entirely. AND id = 'myId' --AND XmlTest.value('(/CodeFiveReport/Owner/AgencyID)[1]', 'nVarChar(128)') IS NULL--Same thing as Exist(), only without the overhead of Casting.
XML Variable
If you only want to update the XML variable (and not the XML field in the table), I would use this approach.
I prefer this because you are not deleting the existing Node or adding it unnecessarily (which I think is slower). You only update it when it is absolutely necessary.
FYI: An element can have the value Text and other child elements - this is permitted by the XML specification.
DECLARE @Xml Xml = N'<Root><Note /></Root>'--Works for: "<Root></Root>", "<Root><Note /></Root>", and "<Root><Note>Something</Note></Root>". DECLARE @Note NVarChar(128) = 'Hello' IF(@Xml.value('(/Root/Note)[1]', 'nVarChar(128)') = '') SET @Xml.modify('insert text{sql:variable("@Note")} as first into (/Root/Note)[1]') --Node is: <Note /> IF(@Xml.value('(/Root/Note)[1]', 'nVarChar(128)') != @Note) SET @Xml.modify('replace value of (/Root/Note/text())[1] with sql:variable("@Note")') --Node is like: <Note>Something<\Note> IF(@Xml.exist('/Root/Note') = 0) SET @Xml.modify('insert <Note>{sql:variable("@Note")}</Note> as first into (/Root)[1]')--Node is missing: <Root></Root> SELECT @Xml[@Xml]
MikeTeeVee
source share