how to get an xml in a variable - sql-server-2005

I have a stored procedure that will return xml. I have delared a variable of type xml and trying to execute the following code
declare #v xml
set #v = execute get_xml #id, 33
whereas id is returned by another query. now it keeps compalinng about the following error
Incorrect syntax near the keyword 'execute'.

Instead of returning it make the XML an OUTPUT parameter and call like
declare #v xml
execute get_xml #id, 33, #v OUTPUT
The definition of the sp will need to be changed as well. example below.
CREATE PROCEDURE get_xml2
#id INT,
#OtherNumber INT,
#XML XML = NULL OUTPUT
AS
SET #XML = '<blah />'

Related

Problem with a dynamic function in SQL Server

I have a table dbo.t_products and I want to know the last record updated. For that I have an attribute last_changed which stores for each record the timestamp of the last update.
Finally I want to save that result in a variable called #y.
DECLARE #y DATETIME
DECLARE #p_table VARCHAR(100)
SET #p_table = 'dbo.t_products'
EXECUTE sp_executesql N'SET #y = SELECT MAX(last_changed) FROM #p_table'
,N'#p_table VARCHAR, #y DATETIME OUTPUT'
,#p_table
,#y OUTPUT
SELECT #y
The system returns the following message:
Msg 156, Level 15, State 1, Line 25
Incorrect syntax near the keyword 'SELECT'.
Any ideas?
The whole point of using dynamic SQL in your case (I assume) is to allow the use of a dynamic table name. In which case you have to insert the table name into the dynamic SQL string - you can't pass it in as a parameter, thats the problem you are trying in the first place.
Also you don't need a SET followed by a SELECT just use SELECT directly to set the variable.
Finally you definitely want to use the QUOTENAME function to escape your table name and avoid an SQL injection attack - this requires you split the table name and schema name.
DECLARE #y DATETIME;
DECLARE #p_schema VARCHAR(100);
DECLARE #p_table VARCHAR(100);
DECLARE #SQL NVARCHAR(max);
SET #p_schema = 'dbo';
SET #p_table = 't_products';
-- Add the table name to the dynamic SQL
SET #SQL = 'SELECT #y = MAX(last_changed) FROM ' + QUOTENAME(#p_schema) + '.' + QUOTENAME(#p_table);
EXECUTE sp_executesql #SQL, N'#y DATETIME OUTPUT', #y OUTPUT;
-- PRINT(#SQL); --- Debugging
SELECT #y;

Create stored procedure first check and insert XML data in SQL server

create procedure [dbo].[usp_xml]
#xml varchar(max),
#jobtransid int
as
if exists ( SELECT ixbrlxml.xml('#xml')
FROM ixbrlxml
CROSS APPLY [xml].nodes('/iXBRLConf/context') as T2(Loc) where jobtransid=#jobtransid)
begin
print 'error'
end
else
begin
UPDATE ixbrlxml
SET [xml].modify('insert #xml (/iXBRLConf/roles)[1]')
where jobtransid=#jobtransid
end
I want to check and insert and update through a stored procedure I have a table that data type is XML
If I execute this I get the error:
Msg 2209, Level 16, State 1, Procedure usp_xml, Line 16 [Batch Start
Line 7] XQuery [ixbrlxml.XML.modify()]: Syntax error near '('
There are three flaws:
You cannot use the variable #xml as literal within the XQuery. There is sql:variable() for your rescue
You are missing into
You are passing the parameter like #xml varchar(max). This should be XML. If there is a good reason to pass a string type, this should be NVARCHAR(MAX). But - as the target is relying on valid XML - I'd use the appropriate type.
Try this
DECLARE #Existing XML='<root><test a="b"/></root>';
DECLARE #xml XML='<NewNode>blah</NewNode>';
SET #Existing.modify('insert sql:variable("#xml") into (/root/test)[1]');
SELECT #Existing;
The result
<root>
<test a="b">
<NewNode>blah</NewNode>
</test>
</root>
UPDATE
And the fourth problem seems to be this:
if exists ( SELECT ixbrlxml.xml('#xml')
FROM ixbrlxml
CROSS APPLY [xml].nodes('/iXBRLConf/context') as T2(Loc) where jobtransid=#jobtransid)
What are you trying to do here?

SQL Server : XML value returns Scalar and seems I need to convert it twice

I have this line of SQL:
DECLARE #temp_Id UNIQUEIDENTIFIER = #data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier')
So, #data is a parameter to my stored procedure. #data XML
I want to pass a value out of the XML into another stored procedure, as you can see it's the Id field in the xml.
#data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier')
This pulls out and converts the Id value to a Uniqueidentifier however when I assign this to a variable and pass it to the stored procedure:
EXEC my_sproc #Id = #temp_Id
I get an error
Msg 137, Level 15, State 2, Procedure Some_Sproc, Line __
Must declare the scalar variable "#tempId".
Looking around, people are suggesting to wrap the #data.value(... in a CONVERT( DATA_TYPE, VALUE ) which seems slightly absurd.
-- EDIT --
I reckon there could also be a chance of my SQL Server Management Studio intellisense being out of sync....
-- CODE --
CREATE PROCEDURE [dbo].[Sproc_CB8PutNotification]
#message_type NVARCHAR(250),
#utc_timestamp DATETIME2,
#data XML
AS
BEGIN TRY
DECLARE #temp_Id UNIQUEIDENTIFIER = #data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier')
EXEC dbo.SaveNotification #Id = #tempId;
END TRY
BEGIN CATCH
-- some catch code
END CATCH
It should work:
CREATE PROCEDURE my_proc
#id UNIQUEIDENTIFIER
AS
SELECT #id;
GO
DECLARE #data XML =
'<metaData><item key="Id" value="903e9859-f8fd-4163-9303-b43f89fe977f"/>
</metaData>';
DECLARE #temp_Id UNIQUEIDENTIFIER
= #data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier');
EXEC my_proc #id = #temp_id;
LiveDemo
I suspect you have GO betweens calls and variable is not visible between batches like:
DECLARE #data XML =
'<metaData>
<item key="Id" value="903e9859-f8fd-4163-9303-b43f89fe977f"/>
</metaData>';
DECLARE #temp_Id UNIQUEIDENTIFIER
= #data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier');
GO
EXEC my_proc #id = #temp_id;
Error(s), warning(s):
Must declare the scalar variable "#temp_id".
LiveDemo2
Or you have nested calls and variable is out of scope.
EDIT:
Typo #temp_id <> #tempId:
DECLARE #temp_Id UNIQUEIDENTIFIER =
#data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier')
EXEC dbo.SaveNotification #Id = #tempId;
Working code
You've mixed two naming conventions. The key point is to be consistent. It can save a lot of headaches.

How can I pass xml data from one sproc to another?

I have 2 sprocs for an assignment, what I'm trying to do is pass the xml output from one sproc to another and put it in a variable, I know ex1.xml_sp1 is returning an int while calling it with EXEC and obviously when trying to select this it returns null because #x is xml data type.
What I want to do is retrieve and store the xml data from sproc 1 in to #x in sproc 2.
Is there any way to do this?
sproc 1:
ALTER PROC [ex1].[xml_sp1]
#careteamid int
as
select CareTeams.CareTeamID, Doctors.DoctorID, Doctors.DoctorName,
CareTeamDoctors.DateJoined, CareTeamDoctors.CurrentMember
from dbo.CareTeamTbl as CareTeams
inner join dbo.CareTeamDoctorTbl as CareTeamDoctors on
CareTeams.CareTeamID = CareTeamDoctors.CareTeamID
inner join dbo.DoctorTbl as Doctors on
CareTeamDoctors.DoctorID=CareTeamDoctors.DoctorID
where CareTeamDoctors.CareTeamID = #careteamid
and CareTeamDoctors.DoctorID = Doctors.DoctorID
for xml auto, root('thedata')
sproc 2:
ALTER PROC [ex1].[xml_sp2]
#careteamid int
as
declare #x xml
exec #x = ex1.xml_sp1
#careteamid = #careteamid
select #x as XMLData
I want to do is retrieve and store the xml data from sproc 1 in to #x in sproc 2.
You could achieve it very easily using OUTPUT parameters:
CREATE PROCEDURE [xml_sp1]
#careteamid INT,
#xml_output XML OUTPUT
AS
BEGIN
SET #xml_output = (SELECT * FROM ... FOR XML AUTO, root('thedata'));
END;
GO
CREATE PROCEDURE [xml_sp2]
#careteamid INT
AS
BEGIN
DECLARE #x XML;
EXEC [xml_sp1]
#careteamid,
#x OUTPUT;
SELECT #x AS XMLData;
END;
GO
And final call:
EXEC [xml_sp2] #careteamid = 1;
LiveDemo
Consider using BEGIN/END block and end each statement with ; to avoid possible nasty problems.
The full list of possible sharing data methods How to Share Data between Stored Procedures by Erland Sommarskog
For the return value (i.e. EXEC #ReturnValue = StoredProcName...;), INT is the only datatype allowed. If this needs to really stay as a Stored Procedure then you can either use an OUTPUT variable or create a temp table or table variable in the second Stored Procedure and do INSERT INTO ... EXEC StoredProc1;.
However, given that the first Stored Procedure is only doing a simple SELECT statement, you would be far better off converting this to be an Inline Table-Valued Function (iTVF) as follows:
CREATE FUNCTION dbo.GetData (#CareTeamID INT)
RETURNS TABLE
AS RETURN
SELECT tab.col AS [CareData]
FROM (
SELECT CareTeams.CareTeamID, Doctors.DoctorID, Doctors.DoctorName,
CareTeamDoctors.DateJoined, CareTeamDoctors.CurrentMember
FROM dbo.CareTeamTbl as CareTeams
INNER JOIN dbo.CareTeamDoctorTbl as CareTeamDoctors
ON CareTeams.CareTeamID = CareTeamDoctors.CareTeamID
INNER JOIN dbo.DoctorTbl as Doctors
ON CareTeamDoctors.DoctorID=CareTeamDoctors.DoctorID
WHERE CareTeamDoctors.CareTeamID = #CareTeamID
AND CareTeamDoctors.DoctorID = Doctors.DoctorID
FOR XML AUTO, ROOT('thedata'), TYPE -- "TYPE" causes result to be XML and not NVARCHAR
) tab(col);
Then just change the second stored procedure to be:
SELECT care.CareData AS [XMLData]
FROM dbo.GetData(#CareTeamID);
Or, if you actually need to make use of that XML data in the second Stored Procedure, do the following:
DECLARE #TempData XML;
SELECT #TempData = care.CareData
FROM dbo.GetData(#CareTeamID);
Finally, if you need the XML data to actually be of the XML datatype coming out of that iTVF (or even if you keep it as a Stored Procedure), then you need to add the TYPE option to the FOR XML clause, else what is returned is a string / NVARCHAR(MAX):
FOR XML AUTO, ROOT ('thedata'), TYPE
Why not try this instead of assigning output of sp1 directly
declare #t table
(
val xml
)
insert into #t
exec ex1.xml_sp1
#careteamid = #careteamid
select * from #t
Will this work?
declare #xml xml
set #xml = (select *
from tableABC
for xml auto, elements)
And then pass that variable to another sproc?
I go the answer from here
How to insert FOR AUTO XML result into table?.
Seems to me the idea is similar, or should work similar.

SQL XML XQUERY - Looks right, NULL/empty value returned

I'm newish to XML XQuery and such but this sure looks like it ought to work.
XML fragment
<Contacts>
<Contact ContactID="7" FileType="MS">
<ID>7</ID>
....
<Comments ContactID="7" />
<CompanyID ContactID="88">Some New Value</CompanyID>
<CompanyName ContactID="7">Some New Value</CompanyName>
</Contact>
</Contacts>
I pass in #SourceField to the stored procedure. In this case its value is CompanyID. I then create a variable I call #xmlPath.
SET #XmlPath = '/Contacts/Contact/' + #SourceField
I retrieve the XML from the table into a variable named #ContactData (see fragment above)
I then create a variable #SqlCmd and execute it.
SET #SqlCmd = 'SET #ContactID = #ContactData.value(''(' + #xmlPath + '/#ContactID)[1]'', ''nvarchar(max)'')'
EXECUTE sp_executesql #SqlCmd, N'#ContactID nvarchar(20), #ContactData XML',#ContactID, #ContactData
I issue three SQL commands to test the values.
SELECT #ContactData AS ContactData
SELECT #SqlCmd AS SqlCmd
SELECT #ContactID AS ContactID
The first returns the XML from the table. (see fragment above)
The second returns the following;
SET #ContactID = #ContactData.value('(/Contacts/Contact/CompanyID/#ContactID)[1]', 'nvarchar(max)')
which looks correct but...
and the third returns NULL when I would expect 88. Also, when I initialize #ContactID = '' I receive the empty string.
So, my conclusion is that I am missing an assignment process somewhere but the code looks like every example I've seen online that does work. I MUST be missing something simple.
Any thoughts?
Thanks!
You need to declare the parameter #ContactID as an output parameter.
Try this:
EXECUTE sp_executesql #SqlCmd, N'#ContactID nvarchar(20) out, #ContactData XML',#ContactID out, #ContactData