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