I'm trying to use sql:variable
to read data from a XML file. My problem is, I can read the first or n^th line (or node) of the XML, however I can't make iteration in the lines (or nodes). Here is where I used sql:variable
:
CAST((SELECT @xmlExpenseItems.value(N'(/ExpenseItem//ExpenseID/node())[sql:variable("@iteratorVarChar")]','int')) AS int),
CAST((SELECT @xmlExpenseItems.value(N'(/ExpenseItem//ExpenseTypeID/node())[sql:variable("@iteratorVarChar")]','int')) AS int),
CAST((SELECT @xmlExpenseItems.value(N'(/ExpenseItem//ExpenseAmount/node())[sql:variable("@iteratorVarChar")]','float')) AS float)
where @iteratorVarChar
is a varchar casted from an int.
I get the error "XQuery [value()]: Only ' http://www.w3.org/2001/XMLSchema#decimal ?', ' http://www.w3.org/2001/XMLSchema#boolean ?' or 'node()*' expressions allowed as predicates, found 'xs:string ?'" at the first line of the code above.
When I switched @iteratorVarChar with @iterator
which is already an int, I get "XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'"
As I said, when I replace sql:variable("@iteratorVarChar")
with an int, like 1
, then the code works with the first node of the xml.
My question is, am I missing something or am I making a fundamental mistake? How to make this work?
My whole code is below (I commented out the CREATE
in order to avoid the recreation errors):
DECLARE @xmlExpenseItems XML
SET @xmlExpenseItems = '
<ExpenseItem>
<ExpenseID>5</ExpenseID>
<ExpenseTypeID>5</ExpenseTypeID>
<ExpenseAmount>5</ExpenseAmount>
</ExpenseItem>
<ExpenseItem>
<ExpenseID>3</ExpenseID>
<ExpenseTypeID>5</ExpenseTypeID>
<ExpenseAmount>7</ExpenseAmount>
</ExpenseItem>
'
--CREATE TABLE #ExpenseItems
--(ExpenseItemID int not null identity(1,1),
--ExpenseID int not null,
--ExpenseTypeID int not null,
--ExpenseAmount float not null
--)
DECLARE @iterator int = 1
DECLARE @IDCount int
SELECT @IDCount = (SELECT @xmlExpenseItems.value('count(/ExpenseItem)', 'int') )
DECLARE @iteratorVarChar varchar(3)
WHILE @iterator <= @IDCount
BEGIN
SET @iteratorVarChar = CAST(@iterator AS varchar(3))
INSERT INTO #ExpenseItems
(ExpenseID, ExpenseTypeID, ExpenseAmount)
VALUES
(
CAST((SELECT @xmlExpenseItems.value(N'(/ExpenseItem//ExpenseID/node())[sql:variable("@iteratorVarChar")]','int')) AS int),
CAST((SELECT @xmlExpenseItems.value(N'(/ExpenseItem//ExpenseTypeID/node())[sql:variable("@iteratorVarChar")]','int')) AS int),
CAST((SELECT @xmlExpenseItems.value(N'(/ExpenseItem//ExpenseAmount/node())[sql:variable("@iteratorVarChar")]','float')) AS float)
)
SET @iterator = @iterator + 1
END
select * from #ExpenseItems
Try a set based approach instead of iteration. The nodes()
function returns a rowset from an XML document:
insert #ExpenseItems
(ExpenseID, ExpenseTypeID, ExpenseAmount)
select col.value('ExpenseID[1]', 'int')
, col.value('ExpenseTypeID[1]', 'int')
, col.value('ExpenseAmount[1]', 'int')
from @xmlExpenseItems.nodes('/ExpenseItem') doc(col)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.