Convert XML Nodes To Rows in SQL Server - sql-server

Consider the below sample:
declare #somexml as xml
set #somexml = '
<Settings>
<Users>
<ID>1</ID>
<ID>2</ID>
<ID>3</ID>
<ID>4</ID>
<ID>5</ID>
</Users>
</Settings>'
The above XML has some ID values that I need to convert to rows of data that can be used in a temp table to perform joins against.
I can't quite get the syntax correct, I've tried a number of samples that I've come across:
SELECT T.r.value('.','int') as id
FROM #somexml.nodes('/Settings/Users') T(r)
Returns:
|ID |
|------|
|12345 |
The following:
SELECT T.r.query('.') as id
from #somexml.nodes('/Settings/Users/ID') as T(r)
Returns:
|ID |
|-----------|
|<ID>1</ID> |
|<ID>2</ID> |
|<ID>3</ID> |
|<ID>4</ID> |
|<ID>5</ID> |
I'm getting close, but I want to remove the XML tags to just leave the ID values like so:
|ID |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
Here's a fiddle if you want to play/solve that way: SQL Fiddle
Any help is appreciated as always.

Replace T.r.query('.') as id with T.r.value('.', 'INT') as id

SELECT T.r.value('.','int') as id
FROM #somexml.nodes('/Settings/Users/ID') T(r)

Related

How to extract array from JSON String in BigQuery

Hi, I'm working on a table looks like below:
----------------------------------------------------------------------------------------------------------------------------------------------
| user_id | j_games_information
----------------------------------------------------------------------------------------------------------------------------------------------
| hsbdgcy76s |{"data": [{"game_id": "acb", "rewards":[{"no":3,"items":"oils"}]},{"game_id": "bsm", "rewards":[{"no":4,"items":"bombs"}]}]}
----------------------------------------------------------------------------------------------------------------------------------------------
| kslcn6vg76 |{"data": [{"game_id": "ohf", "rewards":[{"no":6,"items":"oils"}]},{"game_id": "dfg", "rewards":[{"no":7,"items":"bombs"}]}]}
----------------------------------------------------------------------------------------------------------------------------------------------
My expected output will be:
-----------------------------------
| user_id | game_ids |
-----------------------------------
| hsbdgcy76s | acb |
-----------------------------------
| hsbdgcy76s | bsm |
-----------------------------------
| kslcn6vg76 | ohf |
-----------------------------------
| kslcn6vg76 | dfg |
-----------------------------------
I tried the following code but this query returned no results. Can anyone help me with this? Thank you!
select user_id, JSON_EXRACT_SCALAR(json_array,"$.game_id") AS game_ids
from table, unnest(json_extract_array(j_games_information,"$.data")) AS json_array
But
Try to replace json_file with j_games_information
with mytable as (
select 'hsbdgcy76s' as user_id, '{"data": [{"game_id": "acb", "rewards":[{"no":3,"items":"oils"}]},{"game_id": "bsm", "rewards":[{"no":4,"items":"bombs"}]}]}' as j_games_information union all
select 'kslcn6vg76' as user_id, '{"data": [{"game_id": "ohf", "rewards":[{"no":6,"items":"oils"}]},{"game_id": "dfg", "rewards":[{"no":7,"items":"bombs"}]}]}' as j_games_information
)
select user_id, JSON_EXTRACT_SCALAR(json_array,"$.game_id") AS game_ids
from mytable, unnest(json_extract_array(j_games_information,"$.data")) AS json_array

Get XML namespace text via SQL query

I am working with XML data on an SQL Server. The (exemplary) SQL looks as follows:
<Document xmlns="urn:iso:std:iso:20022:some:test:xmlns">
<Testnode>a</Testnode>
</Document>
The XML is available in a table with a column named <fata of type XML.
My question is: How can I create a SELECT query that shows the text of the namespace in one column?
The expected output should be:
+----------------------------------------+
| xmlns |
+----------------------------------------+
| urn:iso:std:iso:20022:some:test:xmlns |
+----------------------------------------+
The result column should be a character string (no XML).
So far I have tried this query, however the result is NULL:
SELECT Data.value('(./Document)[1]','nvarchar(max)') AS xmlns
FROM xmltable
You can try something along this:
DECLARE #xml XML=
N'<Document xmlns="urn:iso:std:iso:20022:some:test:xmlns">
<Testnode>a</Testnode>
</Document>';
--The XQuery-function namespace-uri() takes a singleton and returns its namespace uri
SELECT #xml.value('namespace-uri((/*:Document)[1])','nvarchar(max)');
As the <Document> element is living within the default namespace itself, we would have to know the namespace in advance in order to declare it. But - luckily - we can use the wildcard with *:.
Another option - one of the rare cases - is the usage of the outdated FROM OPENXML:
Try this:
DECLARE #xml XML=
N'<Document xmlns="urn:iso:std:iso:20022:some:test:xmlns">
<Testnode>a</Testnode>
</Document>';
DECLARE #docHandle INT;
EXEC sp_xml_preparedocument #docHandle OUTPUT, #xml;
SELECT * FROM OPENXML (#docHandle, '/*',1);
EXEC sp_xml_removedocument #docHandle;
This returns the complete XML with a lot of meta-data:
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| id | parentid | nodetype | localname | prefix | namespaceuri | datatype | prev | text |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 0 | NULL | 1 | Document | NULL | urn:iso:std:iso:20022:some:test:xmlns | NULL | NULL | NULL |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 2 | 0 | 2 | xmlns | xmlns | NULL | NULL | NULL | NULL |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 4 | 2 | 3 | #text | NULL | NULL | NULL | NULL | urn:iso:std:iso:20022:some:test:xmlns |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 3 | 0 | 1 | Testnode | NULL | urn:iso:std:iso:20022:some:test:xmlns | NULL | NULL | NULL |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+
| 5 | 3 | 3 | #text | NULL | NULL | NULL | NULL | a |
+----+----------+----------+-----------+--------+---------------------------------------+----------+------+---------------------------------------+

SQL - Parse table of multi-column XML Data

I have a table filled with XML Data that I am trying to parse. The XML contains multiple columns of data that I am trying to parse. In some cases there are multiple rows of XML data stuffed into the single column of data and in some cases just one. sample data below:
<REC><C1>0E5627DF-DBB1-4300-40F2-715A8C96190B</C1><C2>apples</C2></REC>
<REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>oranges</C2></REC><REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>grapes</C2></REC><REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>apples</C2></REC>
<REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>bananas</C2></REC><REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>watermelon</C2></REC><REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>limes</C2></REC>
<REC><C1>38B13BFB-DBAA-C340-40F2-715A8C961942</C1><C2>apples</C2></REC>
<REC><C1>58209738-DB3C-DB00-D01A-7FDA8C9619B5</C1><C2>pears</C2></REC><REC><C1>58209738-DB3C-DB00-D01A-7FDA8C9619B5</C1><C2>limes</C2></REC>
What I am trying to do is parse the data into the following 2 column layout
C1 C2
0E5627DF-DBB1-4300-40F2-715A8C96190B apples
59868DA4-DB9D-1384-B07D-715A8C96197B oranges
59868DA4-DB9D-1384-B07D-715A8C96197B grapes
59868DA4-DB9D-1384-B07D-715A8C96197B apples
7FB8C203-DB30-5340-B07D-715A8C9619FA bananas
7FB8C203-DB30-5340-B07D-715A8C9619FA watermelon
7FB8C203-DB30-5340-B07D-715A8C9619FA limes
38B13BFB-DBAA-C340-40F2-715A8C961942 apples
58209738-DB3C-DB00-D01A-7FDA8C9619B5 pears
58209738-DB3C-DB00-D01A-7FDA8C9619B5 limes
Below is my attempt at it:
SELECT Split.XMLD.value('.', 'VARCHAR(500)')
FROM myTable XMLD
CROSS APPLY XMLD.REC.nodes ('/REC') AS Split(XMLD)
Any ideas how to parse this?
Clarification: I want to stay with Native MS SQL SQL here. I don't want to use any third party tools.
Try this:
DECLARE #mockupTable TABLE (ID INT IDENTITY, YourXml XML);
INSERT INTO #mockupTable VALUES
('<REC><C1>0E5627DF-DBB1-4300-40F2-715A8C96190B</C1><C2>apples</C2></REC>')
,('<REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>oranges</C2></REC><REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>grapes</C2></REC><REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>apples</C2></REC>')
,('<REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>bananas</C2></REC><REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>watermelon</C2></REC><REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>limes</C2></REC>')
,('<REC><C1>38B13BFB-DBAA-C340-40F2-715A8C961942</C1><C2>apples</C2></REC>')
,('<REC><C1>58209738-DB3C-DB00-D01A-7FDA8C9619B5</C1><C2>pears</C2></REC><REC><C1>58209738-DB3C-DB00-D01A-7FDA8C9619B5</C1><C2>limes</C2></REC>');
SELECT ID
,r.value(N'(C1/text())[1]','uniqueidentifier') AS C1
,r.value(N'(C2/text())[1]','nvarchar(max)') AS C2
FROM #mockupTable AS t
CROSS APPLY t.YourXml.nodes(N'/REC') AS A(r) ;
The result
+----+--------------------------------------+------------+
| ID | C1 | C2 |
+----+--------------------------------------+------------+
| 1 | 0E5627DF-DBB1-4300-40F2-715A8C96190B | apples |
+----+--------------------------------------+------------+
| 2 | 59868DA4-DB9D-1384-B07D-715A8C96197B | oranges |
+----+--------------------------------------+------------+
| 2 | 59868DA4-DB9D-1384-B07D-715A8C96197B | grapes |
+----+--------------------------------------+------------+
| 2 | 59868DA4-DB9D-1384-B07D-715A8C96197B | apples |
+----+--------------------------------------+------------+
| 3 | 7FB8C203-DB30-5340-B07D-715A8C9619FA | bananas |
+----+--------------------------------------+------------+
| 3 | 7FB8C203-DB30-5340-B07D-715A8C9619FA | watermelon |
+----+--------------------------------------+------------+
| 3 | 7FB8C203-DB30-5340-B07D-715A8C9619FA | limes |
+----+--------------------------------------+------------+
| 4 | 38B13BFB-DBAA-C340-40F2-715A8C961942 | apples |
+----+--------------------------------------+------------+
| 5 | 58209738-DB3C-DB00-D01A-7FDA8C9619B5 | pears |
+----+--------------------------------------+------------+
| 5 | 58209738-DB3C-DB00-D01A-7FDA8C9619B5 | limes |
+----+--------------------------------------+------------+
Some things to think about:
Your XML is not well-formed. There is no root-node. SQL-Server can deal with such XML fragments, but other comsumers might get in troubles.
If this XML is under your control I'd change the design no to store the C1 value over and over.
Here is a really neat way to easily generate the XQuery/XPath query for any XML data no matter the complexity or "ugliness":
It requires SQLHTTP which is a free database/assembly that we created which you can find on our website at: http://sqlhttp.net/documentation/xqueryhelper
First you need to set an XML variable with your data. Notice that I added a opening tag and closing tag.
DECLARE #X xml = '<ROOT>
<REC><C1>0E5627DF-DBB1-4300-40F2-715A8C96190B</C1><C2>apples</C2></REC>
<REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>oranges</C2></REC><REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>grapes</C2></REC><REC><C1>59868DA4-DB9D-1384-B07D-715A8C96197B</C1><C2>apples</C2></REC>
<REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>bananas</C2></REC><REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>watermelon</C2></REC><REC><C1>7FB8C203-DB30-5340-B07D-715A8C9619FA</C1><C2>limes</C2></REC>
<REC><C1>38B13BFB-DBAA-C340-40F2-715A8C961942</C1><C2>apples</C2></REC>
<REC><C1>58209738-DB3C-DB00-D01A-7FDA8C9619B5</C1><C2>pears</C2></REC><REC><C1>58209738-DB3C-DB00-D01A-7FDA8C9619B5</C1><C2>limes</C2></REC>
</ROOT>'
You then execute the following stored procedure:
EXEC SQLHTTP.net.XqueryHelper #X
In the case, the procedure will output the following four lines:
Usage Name Rows
------------------------------------------------- ------ ------
EXEC SQLHTTP.net.XQueryHelper #X, 'ROOT' ROOT 1
EXEC SQLHTTP.net.XQueryHelper #X, 'ROOT/REC' REC 10
EXEC SQLHTTP.net.XQueryHelper #X, 'ROOT/REC/C1' C1 10
EXEC SQLHTTP.net.XQueryHelper #X, 'ROOT/REC/C2' C2 10
The line you're interested in to get you the ten records with the fruit names is the second line:
EXEC SQLHTTP.net.XQueryHelper #X, 'ROOT/REC'
The above stored procedure call will then output your XQuery/XPath like this:
SELECT T.C.value(N'C1[1]', N'nvarchar(MAX)') AS [C1]
,T.C.value(N'C2[1]', N'nvarchar(MAX)') AS [C2]
FROM #X.nodes(N'/ROOT/REC') T(C)

SQL Server - Is it possible to define a table column as a table?

I know that this is possible in Oracle and I wonder if SQL Server also supports it (searched for answer without success).
It would greatly simplify my life in the current project if I could define a column of a table to be a table itself, something like:
Table A:
Column_1 Column_2
+----------+----------------------------------------+
| 1 | Columns_2_1 Column_2_2 |
| | +-------------+------------------+ |
| | | 'A' | 12345 | |
| | +-------------+------------------+ |
| | | 'B' | 777777 | |
| | +-------------+------------------+ |
| | | 'C' | 888888 | |
| | +-------------+------------------+ |
+----------+----------------------------------------+
| 2 | Columns_2_1 Column_2_2 |
| | +-------------+------------------+ |
| | | 'X' | 555555 | |
| | +-------------+------------------+ |
| | | 'Y' | 666666 | |
| | +-------------+------------------+ |
| | | 'Z' | 000001 | |
| | +-------------+------------------+ |
+----------+----------------------------------------+
Thanks in advance.
There is one option where you can store data as XML
Declare #YourTable table (ID int,XMLData xml)
Insert Into #YourTable values
(1,'<root><ID>1</ID><Active>1</Active><First_Name>John</First_Name><Last_Name>Smith</Last_Name><EMail>john.smith#email.com</EMail></root>')
,(2,'<root><ID>2</ID><Active>0</Active><First_Name>Jane</First_Name><Last_Name>Doe</Last_Name><EMail>jane.doe#email.com</EMail></root>')
Select ID
,Last_Name = XMLData.value('(root/Last_Name)[1]' ,'nvarchar(50)')
,First_Name = XMLData.value('(root/First_Name)[1]' ,'nvarchar(50)')
From #YourTable
Returns
ID Last_Name First_Name
1 Smith John
2 Doe Jane
Actually, for a normalized database we do not require such functionality.
Because if we need to insert a table within a column than we can create a child table and reference it as a foreign key in the parent table.
In spite, if you still insist to such functionality than you can use SQL Server 2016 to support JSON data where you can store any associative list in JSON format.
Like:
DECLARE #json NVARCHAR(4000)
SET #json =
N'{
"info":{
"type":1,
"address":{
"town":"Bristol",
"county":"Avon",
"country":"England"
},
"tags":["Sport", "Water polo"]
},
"type":"Basic"
}'
SELECT
JSON_VALUE(#json, '$.type') as type,
JSON_VALUE(#json, '$.info.address.town') as town,
JSON_QUERY(#json, '$.info.tags') as tags
SELECT value
FROM OPENJSON(#json, '$.info.tags')
In older versions, this can be achieved through xml as shown in previous answer.
Your can also make use of "sql_variant" datatype to map your table.
Previously, I was also in search of such features as available in Oracle. But after reading various articles and blogs from experts, I was convinced, such features will make the things more complex beside helping.
Only storing the data in required format is not important, It is worthy when it is also efficiently available (readable).
Hope this will help you to take your decision.

Consolidating multiple rows of XML values and primary keys into one SQL-queried table

I have a table named VPX_EVENT_ARG where a column, ARG_DATA, contains XML values.
Table 1
+----------+-------------------+----------+
| EVENT_ID | ARG_TYPE | ARG_DATA |
+----------+-------------------+----------+
| 7121001 | vim.vm.ConfigSpec | XML1 |
| 7121002 | vim.vm.ConfigSpec | XML2 |
| 7121003 | vim.vm.ConfigSpec | XML3 |
+----------+-------------------+----------+
XML1, XML2 and XML3 are XML values. They are too long to type in the table. Here are the real values. Actually they appear in one line.
XML1, for example,
<obj xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:vim25" versionId="5.5" xsi:type="VirtualMachineConfigSpec"><changeVersion>2015-09-24T10:02:53.866694Z</changeVersion><files><vmPathName>ds:///vmfs/volumes/54e5d10c-c527b7f3-7eea-a0d3c1f01404/CommVault VM Test/CommVault VM Test.vmx</vmPathName></files><deviceChange><operation>remove</operation><device xsi:type="VirtualDisk"><key>2003</key><deviceInfo><label>Hard disk 4</label><summary>20,971,520 KB </summary></deviceInfo><backing xsi:type="VirtualDiskFlatVer2BackingInfo"><fileName>ds:///vmfs/volumes/54e5d10c-c527b7f3-7eea-a0d3c1f01404/CommVault VM Test/CommVault VM Test_2.vmdk</fileName><diskMode>persistent</diskMode><split>false</split><writeThrough>false</writeThrough><thinProvisioned>false</thinProvisioned><uuid>6000C29b-e652-b5fe-76fa-18f6de988807</uuid><contentId>5bd085f0f9391346751e1e7efffffffe</contentId><digestEnabled>false</digestEnabled></backing><controllerKey>1000</controllerKey><unitNumber>3</unitNumber><capacityInKB>20971520</capacityInKB><shares><shares>1000</shares><level>normal</level></shares><storageIOAllocation><limit>-1</limit><shares><shares>1000</shares><level>normal</level></shares></storageIOAllocation></device></deviceChange></obj>
I will separate XML1 into multiple lines so that it will be easier to read.
<obj xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:vim25" versionId="5.5" xsi:type="VirtualMachineConfigSpec"><changeVersion>2015-09-24T10:02:53.866694Z</changeVersion><files><vmPathName>ds:///vmfs/volumes/54e5d10c-c527b7f3-7eea-a0d3c1f01404/CommVault VM Test/CommVault VM Test.vmx</vmPathName></files>
<deviceChange>
<operation>remove</operation>
<device xsi:type="VirtualDisk">
<key>2003</key>
<deviceInfo>
<label>Hard disk 4</label>
<summary>20,971,520 KB </summary>
</deviceInfo>
<backing xsi:type="VirtualDiskFlatVer2BackingInfo">
<fileName>ds:///vmfs/volumes/54e5d10c-c527b7f3-7eea-a0d3c1f01404/CommVault VM Test/CommVault VM Test_2.vmdk
</fileName>
<diskMode>persistent</diskMode>
<split>false</split>
<writeThrough>false</writeThrough>
<thinProvisioned>false</thinProvisioned>
<uuid>6000C29b-e652-b5fe-76fa-18f6de988807</uuid>
<contentId>5bd085f0f9391346751e1e7efffffffe</contentId>
<digestEnabled>false</digestEnabled>
</backing>
<controllerKey>1000</controllerKey>
<unitNumber>3</unitNumber>
<capacityInKB>20971520</capacityInKB>
<shares><shares>1000</shares><level>normal</level></shares><storageIOAllocation><limit>-1</limit><shares><shares>1000</shares><level>normal</level></shares></storageIOAllocation>
</device>
</deviceChange>
</obj>
I would like to extract XML1 into tables using an MSSQL query.
DECLARE #xml XML
SET #xml = (SELECT ARG_DATA FROM VPX_EVENT_ARG WHERE ARG_ID = 1 AND EVENT_ID = 7121001); --EVENT_ID is fixed.
WITH XMLNAMESPACES('urn:vim25' AS NS)
SELECT
'diskUnit' = ref.value('./NS:device[1]/NS:unitNumber[1]', 'INT'),
'operation' = ref.value('./NS:operation[1]', 'NVARCHAR(100)'),
'newSizeKB' = ref.value('./NS:device[1]/NS:capacityInKB[1]', 'BIGINT')
FROM #xml.nodes('/NS:obj/NS:deviceChange') data(ref)
Well, I get this as a result.
Table 2
+------+-----------+-----------+
| unit | operation | newSizeKB |
+------+-----------+-----------+
| 1 | edit | 24117248 |
| 2 | edit | 108003328 |
| 3 | add | 20971520 |
+------+-----------+-----------+
You can see that Table 2 is just the result of the first row in Table 1. Not even the first row, it is just ARG_DATA on the first row which fixes EVENT_ID as well. I wish anyone can help.
Question 1: I would like to consolidate multiple rows of XML values into one table without fixing EVENT_IDs and put EVENT_IDs into a column too. Please assume that VPX_EVENT_ARG table contains hundreds of rows.
Table3
+----------+------+-----------+-----------+
| EVENT_ID | unit | operation | newSizeKB |
+----------+------+-----------+-----------+
| 7121001 | 1 | edit | 24117248 |
| 7121001 | 2 | edit | 108003328 |
| 7121001 | 3 | add | 20971520 |
| 7121002 | 1 | edit | 1048576 |
| 7121002 | 3 | edit | 52428800 |
| 7121003 | 3 | edit | 125829120 |
| 7121003 | 5 | remove | 83886080 |
+----------+------+-----------+-----------+
Question 2: Is there a way to use the query without setting XML? I need to set XML for the query, then I can use nodes().
SET #xml = (SELECT ARG_DATA FROM VPX_EVENT_ARG WHERE ARG_ID = 1 AND EVENT_ID = 7121001);
.
.
FROM #xml.nodes('/NS:obj/NS:deviceChange') data(ref)
I wonder if it can be done like this.
FROM (SELECT ARG_DATA FROM VPX_EVENT_ARG WHERE ARG_ID = 1 AND EVENT_ID = 7121001).nodes('/NS:obj/NS:deviceChange') data(ref)
Error: Incorrect syntax near '.'. Expecting AS, ID, or QUOTED_ID.
I really want to use such a result as Table3 to join the table I have queried before. I have hard time dealing with XML but stuck at this so long. By the way, I cannot update the table; it is restricted.
Of couse, you can. Use cross apply on your nodes:
;WITH XMLNAMESPACES('urn:vim25' AS NS)
SELECT
v.EVENT_ID,
'diskUnit' = ref.value('./NS:device[1]/NS:unitNumber[1]', 'INT'),
'operation' = ref.value('./NS:operation[1]', 'NVARCHAR(100)'),
'newSizeKB' = ref.value('./NS:device[1]/NS:capacityInKB[1]', 'BIGINT')
FROM VPX_EVENT_ARG AS v
CROSS APPLY v.ARG_DATA.nodes('/NS:obj/NS:deviceChange') data(ref)
If your column is not XML, we need a subquery to convert it:
;WITH XMLNAMESPACES('urn:vim25' AS NS)
SELECT
v.EVENT_ID,
'diskUnit' = ref.value('./NS:device[1]/NS:unitNumber[1]', 'INT'),
'operation' = ref.value('./NS:operation[1]', 'NVARCHAR(100)'),
'newSizeKB' = ref.value('./NS:device[1]/NS:capacityInKB[1]', 'BIGINT')
FROM
(
SELECT
c.EVENT_ID,
c.ARG_TYPE,
CONVERT(xml,c.ARG_DATA) AS ARG_DATA,
c.ARG_ID
FROM VPX_EVENT_ARG AS c
) AS v
CROSS APPLY v.ARG_DATA.nodes('/NS:obj/NS:deviceChange') data(ref)

Resources