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

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.

Related

How to exec a stored procedure for a list of constant values?

I can exec a stored procedure for a single value easily:
EXEC FooStored #ID = 269
But how can I execute the same stored for many values, which I have in a list (I have a comma separated list of about 1000 constant values, which came from outside of SQL).
I was thinking something along the lines of:
EXEC FooStored #ID IN (269,270,274,280,282,292,300,320,324) -- doesn't work
Edit: Since I don't have permissions to alter this procedure or make new stored procedures to this DB, I would prefer to solve this on the querying level, rather than ask someone to make the needed changes for me.
Below is an example using a table-valued parameter.
I see from your comment on the string-splitting answer that you don't want to modify the existing stored procedure interface. Consider creating a new stored procedure for the list interface or overloading the existing interface with the optional list parameter to avoid a breaking change.
CREATE TYPE dbo.IntegerList AS TABLE(
IntegerValue int NOT NULL PRIMARY KEY
)
GO
CREATE PROC dbo.FooStored
#IntegerList dbo.IntegerList READONLY
AS
SELECT *
FROM dbo.YourTable
WHERE ID IN(
SELECT IntegerValue
FROM #IntegerList
);
GO
DECLARE #IntegerList dbo.IntegerList;
INSERT INTO #IntegerList VALUES(269),(270),(274),(280),(282),(292),(300),(320),(324);
EXEC dbo.FooStored #IntegerList = #IntegerList;
GO
You should use Table types
In your stored procedure use a user defined table type as type of your value.
it could be some thing like this:
CREATE PROCEDURE FooStored
(
#IDs ListOfID READONLY
)
AS
.
.
.
ListOfID is a user defined table type as you can see it below:
CREATE TYPE ListOfID AS TABLE
(
[ID] int NULL
)
to use your FooStored stored procedure you must at first declare a temp table and insert your data into that temp Table and pass your it to your stored procedure.
it could be some thing like this:
DECLARE #list ListOfID
INSERT INTO #list VALUES(1)
INSERT INTO #list VALUES(2)
EXEC FooStored #list
You need to take parameter as comma separated string into stored procedure, and then check inside the stored procedure "if '#ID' is in the list."
If you are using SQL Server 2016 and above you can use SPLIT_STRING() function.
If you are using lower version of SQL Server then you can use this function to split the string:
CREATE FUNCTION dbo.splitstring ( #stringToSplit VARCHAR(MAX) )
RETURNS
#returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN
DECLARE #name NVARCHAR(255)
DECLARE #pos INT
WHILE CHARINDEX(',', #stringToSplit) > 0
BEGIN
SELECT #pos = CHARINDEX(',', #stringToSplit)
SELECT #name = SUBSTRING(#stringToSplit, 1, #pos-1)
INSERT INTO #returnList
SELECT #name
SELECT #stringToSplit = SUBSTRING(#stringToSplit, #pos+1, LEN(#stringToSplit)-#pos)
END
INSERT INTO #returnList
SELECT #stringToSplit
RETURN
END
To split the string inside stored procedure:
IF (#ID IN (SELECT * FROM dbo.splitstring(#CommaSeparatedString))
NB! Be careful with white spaces when using above splitstring function. For values like '269, 270, 274' -> space after commas:
IF (#ID IN (SELECT RTRIM(LTRIM([Name])) FROM dbo.splitstring(#CommaSeparatedString))
As #ikram and #DanGuzman said, the only way to do this, without editing the existing procedure or making a new one, is to just exec the stored N times. The query can be built quite fast with for example Vim.
Starting from the file (a lot more numbers in reality):
269,270,274,280,282,292,300,320,324
And running the commands:
qqf,s<Enter><Esc>q
1000#q
<C-V>ggIEXEC FooStored #ID =
Result:
EXEC FooStored #ID = 269
EXEC FooStored #ID = 270
EXEC FooStored #ID = 274
EXEC FooStored #ID = 280
EXEC FooStored #ID = 282
EXEC FooStored #ID = 292
EXEC FooStored #ID = 300
EXEC FooStored #ID = 320
EXEC FooStored #ID = 324

Return Varchar value from Stored Procedure

I have the following basic stored Procedure which return varchar value
create proc myproc
AS
return 'SSS'
Now when I call this stored procedure using the following query
declare #ret varchAR(max)
exec sp_executesql N'exec #ret =procc',
N'#ret varchar(MAX) OUTPUT',#ret = #ret OUTPUT select #ret as result
I get error the following error
Conversion failed when converting the varchar value 'SSS' to data type int.
Kindly help.
Thanks
Stored procedures in MS SQL Sever can only return an Integer.
Did you want to use an output parameter instead?
CREATE PROC [myproc]
#output VARCHAR(3) OUTPUT
AS
SET #output = 'SSS';
RETURN 0;
Which you could call like this,
DECLARE #output VARCHAR(3);
EXEC [myproc] #output OUTPUT;
SELECT #output;
Or maybe you'd prefer to return a scalar result set?
CREATE PROC [myproc]
AS
SELECT 'SSS';
RETURN 0;
which would return the same by simply executing,
EXEC [myproc];
Since stored procedures in MS SQL Sever can only return an Integer, try selecting the value rather than returning it:
create proc myproc AS SELECT 'SSS'
Have output parameter
create proc myproc
(#value varchar(100) output)
AS
select #value='SSS'
GO
declare #ret varchAR(max)
exec sp_executesql N'exec #ret =procc',
N'#ret varchar(MAX) OUTPUT',#ret = #ret OUTPUT select #ret as result
If you want to return a value from stored procedure, you have to declare an output parameter for that.
Hope the below code will help you
create proc myproc
#outputvalue VARCHAR (16) output
AS
set #outputvalue='SSS'
select #outputvalue
alter procedure GetPrueba(#a int, #b int, #Suma INT OUTPUT, #Resta int OUTPUT) as
begin
select #Suma=#a+#b, #Resta=#a- #b
end
alter procedure getprueba2 as
begin
declare #s int, #r int
exec getprueba 2,5, #s OUTPUT, #r OUTPUT
select #s,#r
end
getprueba2

int is incompatible with uniqueidentifier when no int usage

I am getting this error when there is absolutely no usage of int anywhere.
I have this stored procedure
ALTER procedure [dbo].[usp_GetFileGuid] #fileType varchar(25)
as
select [id] from fileTypes where dirId = #fileType
Here id is a uniqueidentifier in fileTypes table
When I execute the following
declare #fileGuid uniqueidentifier
exec #fileGuid = usp_GetFileGuid 'accounts'
print #fileGuid
I get the following error
(1 row(s) affected)
Msg 206, Level 16, State 2, Procedure usp_GetFileGuid, Line 0
Operand type clash: int is incompatible with uniqueidentifier
Is there anything wrong with the syntax of assigning output of stored procedure to the local variable? Thank you.
You are using EXEC #fileGuid = procedure syntax which is used for retrieving return values, not resultsets. Return values are restricted to INT and should only be used to return status / error codes, not data.
What you want to do is use an OUTPUT parameter:
ALTER procedure [dbo].[usp_GetFileGuid]
#fileType varchar(25),
#id UNIQUEIDENTIFIER OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #id = [id] from dbo.fileTypes where dirId = #fileType;
-- if the procedure *also* needs to return this as a resultset:
SELECT [id] = #id;
END
GO
Then for usage:
declare #fileGuid uniqueidentifier;
exec dbo.usp_GetFileGuid #fileType = 'accounts', #id = #fileGuid OUTPUT;
print #fileGuid;
create procedure [dbo].[usp_GetFileGuid] #fileType varchar(25),#uuid uniqueidentifier output
as
select #uuid=[id] from fileTypes where dirId = #fileType
declare #fileGuid uniqueidentifier
exec usp_GetFileGuid 'accounts',#fileGuid output
print #fileGuid
The value returned is an int as it is the status of the execution
From CREATE PROCEDURE (Transact-SQL)
Return a status value to a calling procedure or batch to indicate
success or failure (and the reason for failure).
You are looking for an output parameter.
OUT | OUTPUT
Indicates that the parameter is an output parameter. Use
OUTPUT parameters to return values to the caller of the procedure.
text, ntext, and image parameters cannot be used as OUTPUT parameters,
unless the procedure is a CLR procedure. An output parameter can be a
cursor placeholder, unless the procedure is a CLR procedure. A
table-value data type cannot be specified as an OUTPUT parameter of a
procedure.

Store the result of a stored procedure without using an output parameter

I have 2 stored procedures: up_proc1 and up_proc2.
This is (a simplified version of) up_proc2:
CREATE PROCEDURE dbo.up_proc2
#id_campaign uniqueidentifier, #id_subcampaign uniqueidentifier,
#id_lead uniqueidentifier, #offer NVARCHAR(1000) = NULL
AS
SET NOCOUNT ON
DECLARE #id UNIQUEIDENTIFIER
SELECT #id = id FROM prospects WHERE id_lead = #id_lead
AND id_campaign = #id_campaign AND id_subcampaign = #id_subcampaign
IF #id IS NULL
BEGIN
SET #id = newid ()
INSERT INTO prospects (id, id_campaign, id_subcampaign, id_lead, offer)
values (#id, #id_campaign, #id_subcampaign, #id_lead, #offer)
END
ELSE
BEGIN
UPDATE prospects set offer = #offer WHERE id=#id
END
SELECT #id AS ID
GO
From up_proc1 I call up_proc2. What I would like to achieve is to store the #id of up_proc2 in a variable declared in up_proc1. Is this possible without using an output parameter?
This is how up_proc1 looks like:
CREATE PROCEDURE dbo.up_proc1
AS
SET NOCOUNT ON
DECLARE #fromProc2 UNIQUEIDENTIFIER
-- NOT WORKING
-- select #fromProc2 = exec up_insertProspects [snip]
-- ALSO NOT WORKING
-- exec #fromProc2 = up_insertProspects [snip]
What you could do is store the output into a table variable:
DECLARE #tmpTable TABLE (ID UNIQUEIDENTIFIER)
INSERT INTO #tmpTable
EXEC dbo.up_proc2 ..........
and then go from there and use that table variable later on.
You can certainly consume this as an output parameter in proc2 without affecting how your C# code retrieves the eventual resultset.
ALTER PROCEDURE dbo.up_proc2
#id_campaign uniqueidentifier,
#id_subcampaign uniqueidentifier,
#id_lead uniqueidentifier,
#offer NVARCHAR(1000) = NULL,
#fromProc2 UNIQUEIDENTIFER = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
...
C# can ignore the new parameter since it is nullable (but since a single output parameter is more efficient than a data reader, you may consider updating your C# code to take advantage of the output parameter later).
Now in proc1:
ALTER PROCEDURE dbo.up_proc1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #fromProc2 UNIQUEIDENTIFIER;
EXEC dbo.up_proc2
--... other parameters ...,
#fromProc2 = #fromProc2 OUTPUT;
-- now you can use #fromProc2
END
GO

how to get an xml in a variable

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 />'